diff --git a/.github/actions/people/action.yml b/.github/actions/people/action.yml
new file mode 100644
index 00000000..c00cce84
--- /dev/null
+++ b/.github/actions/people/action.yml
@@ -0,0 +1,26 @@
+name: 'Update People Action'
+description: 'Retrieves people information from GitHub, saves it in people.yaml and opens a PR'
+inputs:
+ token:
+ description: 'User token for accessing the GitHub API. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
+ required: true
+
+runs:
+ using: 'composite'
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: set up python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+
+ - name: install deps
+ run: pip install -U PyGithub pyyaml pydantic pydantic-settings
+ shell: bash
+
+ - name: update people
+ run: python .github/actions/people/people.py
+ shell: bash
+ env:
+ INPUT_TOKEN: ${{ inputs.token }}
diff --git a/.github/actions/people/people.py b/.github/actions/people/people.py
new file mode 100644
index 00000000..3873b658
--- /dev/null
+++ b/.github/actions/people/people.py
@@ -0,0 +1,640 @@
+"""Use the github API to get lists of people who have contributed in various ways to reflect-cpp.
+
+The script is borrowed from the
+[pydantic project](https://github.com/pydantic/pydantic/blob/main/.github/actions/people/people.py),
+and modified to work with the reflect-cpp repository.
+
+Originally, the logic comes from
+[FastAPI](https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py).
+"""
+
+import logging
+
+import subprocess
+import sys
+from collections import Counter
+from datetime import datetime, timedelta, timezone
+from pathlib import Path
+from typing import Any, Container, Dict, List, Set, Union
+
+import requests
+import yaml
+from github import Github
+from pydantic_settings import BaseSettings
+
+from pydantic import BaseModel, SecretStr
+
+github_graphql_url = "https://api.github.com/graphql"
+
+discussions_query = """
+query Q($after: String) {
+ repository(name: "reflect-cpp", owner: "getml") {
+ discussions(first: 100, after: $after) {
+ edges {
+ cursor
+ node {
+ number
+ author {
+ login
+ avatarUrl
+ url
+ }
+ title
+ createdAt
+ comments(first: 100) {
+ nodes {
+ createdAt
+ author {
+ login
+ avatarUrl
+ url
+ }
+ isAnswer
+ replies(first: 10) {
+ nodes {
+ createdAt
+ author {
+ login
+ avatarUrl
+ url
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+"""
+
+issues_query = """
+query Q($after: String) {
+ repository(name: "reflect-cpp", owner: "getml") {
+ issues(first: 100, after: $after) {
+ edges {
+ cursor
+ node {
+ number
+ author {
+ login
+ avatarUrl
+ url
+ }
+ title
+ createdAt
+ state
+ comments(first: 100) {
+ nodes {
+ createdAt
+ author {
+ login
+ avatarUrl
+ url
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+"""
+
+prs_query = """
+query Q($after: String) {
+ repository(name: "reflect-cpp", owner: "getml") {
+ pullRequests(first: 100, after: $after) {
+ edges {
+ cursor
+ node {
+ number
+ labels(first: 100) {
+ nodes {
+ name
+ }
+ }
+ author {
+ login
+ avatarUrl
+ url
+ }
+ title
+ createdAt
+ state
+ comments(first: 100) {
+ nodes {
+ createdAt
+ author {
+ login
+ avatarUrl
+ url
+ }
+ }
+ }
+ reviews(first:100) {
+ nodes {
+ author {
+ login
+ avatarUrl
+ url
+ }
+ state
+ }
+ }
+ }
+ }
+ }
+ }
+}
+"""
+
+
+class Author(BaseModel):
+ login: str
+ avatarUrl: str
+ url: str
+
+
+# Issues and Discussions
+
+
+class CommentsNode(BaseModel):
+ createdAt: datetime
+ author: Union[Author, None] = None
+
+
+class Replies(BaseModel):
+ nodes: List[CommentsNode]
+
+
+class DiscussionsCommentsNode(CommentsNode):
+ replies: Replies
+
+
+class Comments(BaseModel):
+ nodes: List[CommentsNode]
+
+
+class DiscussionsComments(BaseModel):
+ nodes: List[DiscussionsCommentsNode]
+
+
+class IssuesNode(BaseModel):
+ number: int
+ author: Union[Author, None] = None
+ title: str
+ createdAt: datetime
+ state: str
+ comments: Comments
+
+
+class DiscussionsNode(BaseModel):
+ number: int
+ author: Union[Author, None] = None
+ title: str
+ createdAt: datetime
+ comments: DiscussionsComments
+
+
+class IssuesEdge(BaseModel):
+ cursor: str
+ node: IssuesNode
+
+
+class DiscussionsEdge(BaseModel):
+ cursor: str
+ node: DiscussionsNode
+
+
+class Issues(BaseModel):
+ edges: List[IssuesEdge]
+
+
+class Discussions(BaseModel):
+ edges: List[DiscussionsEdge]
+
+
+class IssuesRepository(BaseModel):
+ issues: Issues
+
+
+class DiscussionsRepository(BaseModel):
+ discussions: Discussions
+
+
+class IssuesResponseData(BaseModel):
+ repository: IssuesRepository
+
+
+class DiscussionsResponseData(BaseModel):
+ repository: DiscussionsRepository
+
+
+class IssuesResponse(BaseModel):
+ data: IssuesResponseData
+
+
+class DiscussionsResponse(BaseModel):
+ data: DiscussionsResponseData
+
+
+# PRs
+
+
+class LabelNode(BaseModel):
+ name: str
+
+
+class Labels(BaseModel):
+ nodes: List[LabelNode]
+
+
+class ReviewNode(BaseModel):
+ author: Union[Author, None] = None
+ state: str
+
+
+class Reviews(BaseModel):
+ nodes: List[ReviewNode]
+
+
+class PullRequestNode(BaseModel):
+ number: int
+ labels: Labels
+ author: Union[Author, None] = None
+ title: str
+ createdAt: datetime
+ state: str
+ comments: Comments
+ reviews: Reviews
+
+
+class PullRequestEdge(BaseModel):
+ cursor: str
+ node: PullRequestNode
+
+
+class PullRequests(BaseModel):
+ edges: List[PullRequestEdge]
+
+
+class PRsRepository(BaseModel):
+ pullRequests: PullRequests
+
+
+class PRsResponseData(BaseModel):
+ repository: PRsRepository
+
+
+class PRsResponse(BaseModel):
+ data: PRsResponseData
+
+
+class Settings(BaseSettings):
+ input_token: SecretStr
+ github_repository: str = "getml/reflect-cpp"
+ request_timeout: int = 30
+
+
+def get_graphql_response(
+ *,
+ settings: Settings,
+ query: str,
+ after: Union[str, None] = None,
+) -> Dict[str, Any]:
+ headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
+ variables = {"after": after}
+ response = requests.post(
+ github_graphql_url,
+ headers=headers,
+ timeout=settings.request_timeout,
+ json={"query": query, "variables": variables, "operationName": "Q"},
+ )
+ if response.status_code != 200:
+ logging.error(f"Response was not 200, after: {after}")
+ logging.error(response.text)
+ raise RuntimeError(response.text)
+ data = response.json()
+ if "errors" in data:
+ logging.error(f"Errors in response, after: {after}")
+ logging.error(data["errors"])
+ logging.error(response.text)
+ raise RuntimeError(response.text)
+ return data
+
+
+def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None):
+ data = get_graphql_response(settings=settings, query=issues_query, after=after)
+ graphql_response = IssuesResponse.model_validate(data)
+ return graphql_response.data.repository.issues.edges
+
+
+def get_graphql_question_discussion_edges(
+ *,
+ settings: Settings,
+ after: Union[str, None] = None,
+):
+ data = get_graphql_response(
+ settings=settings,
+ query=discussions_query,
+ after=after,
+ )
+ graphql_response = DiscussionsResponse.model_validate(data)
+ return graphql_response.data.repository.discussions.edges
+
+
+def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None):
+ data = get_graphql_response(settings=settings, query=prs_query, after=after)
+ graphql_response = PRsResponse.model_validate(data)
+ return graphql_response.data.repository.pullRequests.edges
+
+
+def get_issues_experts(settings: Settings):
+ issue_nodes: List[IssuesNode] = []
+ issue_edges = get_graphql_issue_edges(settings=settings)
+
+ while issue_edges:
+ for edge in issue_edges:
+ issue_nodes.append(edge.node)
+ last_edge = issue_edges[-1]
+ issue_edges = get_graphql_issue_edges(settings=settings, after=last_edge.cursor)
+
+ commentors = Counter()
+ last_month_commentors = Counter()
+ authors: Dict[str, Author] = {}
+
+ now = datetime.now(tz=timezone.utc)
+ one_month_ago = now - timedelta(days=30)
+
+ for issue in issue_nodes:
+ issue_author_name = None
+ if issue.author:
+ authors[issue.author.login] = issue.author
+ issue_author_name = issue.author.login
+ issue_commentors = set()
+ for comment in issue.comments.nodes:
+ if comment.author:
+ authors[comment.author.login] = comment.author
+ if comment.author.login != issue_author_name:
+ issue_commentors.add(comment.author.login)
+ for author_name in issue_commentors:
+ commentors[author_name] += 1
+ if issue.createdAt > one_month_ago:
+ last_month_commentors[author_name] += 1
+
+ return commentors, last_month_commentors, authors
+
+
+def get_discussions_experts(settings: Settings):
+ discussion_nodes: List[DiscussionsNode] = []
+ discussion_edges = get_graphql_question_discussion_edges(settings=settings)
+
+ while discussion_edges:
+ for discussion_edge in discussion_edges:
+ discussion_nodes.append(discussion_edge.node)
+ last_edge = discussion_edges[-1]
+ discussion_edges = get_graphql_question_discussion_edges(
+ settings=settings, after=last_edge.cursor
+ )
+
+ commentors = Counter()
+ last_month_commentors = Counter()
+ authors: Dict[str, Author] = {}
+
+ now = datetime.now(tz=timezone.utc)
+ one_month_ago = now - timedelta(days=30)
+
+ for discussion in discussion_nodes:
+ discussion_author_name = None
+ if discussion.author:
+ authors[discussion.author.login] = discussion.author
+ discussion_author_name = discussion.author.login
+ discussion_commentors = set()
+ for comment in discussion.comments.nodes:
+ if comment.author:
+ authors[comment.author.login] = comment.author
+ if comment.author.login != discussion_author_name:
+ discussion_commentors.add(comment.author.login)
+ for reply in comment.replies.nodes:
+ if reply.author:
+ authors[reply.author.login] = reply.author
+ if reply.author.login != discussion_author_name:
+ discussion_commentors.add(reply.author.login)
+ for author_name in discussion_commentors:
+ commentors[author_name] += 1
+ if discussion.createdAt > one_month_ago:
+ last_month_commentors[author_name] += 1
+ return commentors, last_month_commentors, authors
+
+
+def get_experts(settings: Settings):
+ # Migrated to only use GitHub Discussions
+ # (
+ # issues_commentors,
+ # issues_last_month_commentors,
+ # issues_authors,
+ # ) = get_issues_experts(settings=settings)
+ (
+ discussions_commentors,
+ discussions_last_month_commentors,
+ discussions_authors,
+ ) = get_discussions_experts(settings=settings)
+ # commentors = issues_commentors + discussions_commentors
+ commentors = discussions_commentors
+ # last_month_commentors = (
+ # issues_last_month_commentors + discussions_last_month_commentors
+ # )
+ last_month_commentors = discussions_last_month_commentors
+ # authors = {**issues_authors, **discussions_authors}
+ authors = {**discussions_authors}
+ return commentors, last_month_commentors, authors
+
+
+def get_contributors(settings: Settings):
+ pr_nodes: List[PullRequestNode] = []
+ pr_edges = get_graphql_pr_edges(settings=settings)
+
+ while pr_edges:
+ for edge in pr_edges:
+ pr_nodes.append(edge.node)
+ last_edge = pr_edges[-1]
+ pr_edges = get_graphql_pr_edges(settings=settings, after=last_edge.cursor)
+
+ contributors = Counter()
+ commentors = Counter()
+ reviewers = Counter()
+ authors: Dict[str, Author] = {}
+
+ for pr in pr_nodes:
+ author_name = None
+ if pr.author:
+ authors[pr.author.login] = pr.author
+ author_name = pr.author.login
+ pr_commentors: Set[str] = set()
+ pr_reviewers: Set[str] = set()
+ for comment in pr.comments.nodes:
+ if comment.author:
+ authors[comment.author.login] = comment.author
+ if comment.author.login == author_name:
+ continue
+ pr_commentors.add(comment.author.login)
+ for author_name in pr_commentors:
+ commentors[author_name] += 1
+ for review in pr.reviews.nodes:
+ if review.author:
+ authors[review.author.login] = review.author
+ pr_reviewers.add(review.author.login)
+ for reviewer in pr_reviewers:
+ reviewers[reviewer] += 1
+ if pr.state == "MERGED" and pr.author:
+ contributors[pr.author.login] += 1
+ return contributors, commentors, reviewers, authors
+
+
+def get_top_users(
+ *,
+ counter: Counter,
+ min_count: int,
+ authors: Dict[str, Author],
+ skip_users: Container[str],
+):
+ users = []
+ for commentor, count in counter.most_common(50):
+ if commentor in skip_users:
+ continue
+ if count >= min_count:
+ author = authors[commentor]
+ users.append(
+ {
+ "login": commentor,
+ "count": count,
+ "avatarUrl": author.avatarUrl,
+ "url": author.url,
+ }
+ )
+ return users
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
+ settings = Settings() # type: ignore[reportCallIssue]
+ logging.info(f"Using config: {settings.model_dump_json()}")
+ g = Github(settings.input_token.get_secret_value())
+ repo = g.get_repo(settings.github_repository)
+ question_commentors, question_last_month_commentors, question_authors = get_experts(
+ settings=settings
+ )
+ contributors, pr_commentors, reviewers, pr_authors = get_contributors(
+ settings=settings
+ )
+ authors = {**question_authors, **pr_authors}
+ maintainers_logins = {"liuzicheng1987", "Urfoex"}
+ bot_names = {"github-actions"}
+ maintainers = []
+ for login in maintainers_logins:
+ user = authors[login]
+ maintainers.append(
+ {
+ "login": login,
+ "answers": question_commentors[login],
+ "prs": contributors[login],
+ "avatarUrl": user.avatarUrl,
+ "url": user.url,
+ }
+ )
+
+ min_count_expert = 1
+ min_count_last_month = 1
+ min_count_contributor = 1
+ min_count_reviewer = 1
+ skip_users = maintainers_logins | bot_names
+ experts = get_top_users(
+ counter=question_commentors,
+ min_count=min_count_expert,
+ authors=authors,
+ skip_users=skip_users,
+ )
+ last_month_active = get_top_users(
+ counter=question_last_month_commentors,
+ min_count=min_count_last_month,
+ authors=authors,
+ skip_users=skip_users,
+ )
+ top_contributors = get_top_users(
+ counter=contributors,
+ min_count=min_count_contributor,
+ authors=authors,
+ skip_users=skip_users,
+ )
+ top_reviewers = get_top_users(
+ counter=reviewers,
+ min_count=min_count_reviewer,
+ authors=authors,
+ skip_users=skip_users,
+ )
+
+ people = {
+ "maintainers": maintainers,
+ "experts": experts,
+ "last_month_active": last_month_active,
+ "top_contributors": top_contributors,
+ "top_reviewers": top_reviewers,
+ }
+ people_path = Path("./docs/plugins/people.yml")
+ if not people_path.exists():
+ people_path.parent.mkdir(parents=True, exist_ok=True)
+ people_path.touch()
+ people_old_content = people_path.read_text(encoding="utf-8")
+ new_people_content = yaml.dump(
+ people, sort_keys=False, width=200, allow_unicode=True
+ )
+ if people_old_content == new_people_content:
+ logging.info("The people data hasn't changed, finishing.")
+ sys.exit(0)
+ people_path.write_text(new_people_content, encoding="utf-8")
+
+ logging.info("Setting up GitHub Actions git user")
+ subprocess.run(["git", "config", "user.name", "github-actions"], check=True)
+ subprocess.run(
+ ["git", "config", "user.email", "github-actions@github.com"], check=True
+ )
+
+ branch_name = "people-update"
+ logging.info(f"Creating a new branch {branch_name}")
+ subprocess.run(["git", "checkout", "-b", branch_name], check=True)
+ logging.info("Adding updated file")
+ subprocess.run(["git", "add", str(people_path)], check=True)
+ logging.info("Committing updated file")
+ message = "Update People information in documentation"
+ result = subprocess.run(["git", "commit", "-m", message], check=True)
+
+ remote_branch_exists = subprocess.run(
+ ["git", "ls-remote", "--heads", "origin", branch_name],
+ capture_output=True,
+ text=True,
+ ).stdout.strip()
+
+ if remote_branch_exists:
+ logging.info(f"Remote branch {branch_name} exists. Deleting it.")
+ subprocess.run(["git", "push", "origin", "--delete", branch_name], check=True)
+
+ logging.info("Pushing branch")
+ subprocess.run(["git", "push", "origin", branch_name], check=True)
+ logging.info("Creating PR")
+ body = """
+ This PR is created automatically by `update-people` GitHub workflow to update
+ the People information in the documentation. The workflow runs every first day
+ of a month.
+ """
+ pr = repo.create_pull(
+ title=message,
+ body=body,
+ # base branch needs to be changed to main once
+ # feature branch is merged into main
+ base="main",
+ head=branch_name,
+ )
+ logging.info(f"Created PR: {pr.number}")
+ logging.info("Finished")
diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml
index d2eaa1ea..b98ea772 100644
--- a/.github/workflows/jekyll-gh-pages.yml
+++ b/.github/workflows/jekyll-gh-pages.yml
@@ -3,8 +3,8 @@ name: Deploy Jekyll with GitHub Pages dependencies preinstalled
on:
# Runs on pushes targeting the default branch
- push:
- branches: ["main"]
+ # push:
+ # branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
diff --git a/.github/workflows/mkdocs-gh-pages.yaml b/.github/workflows/mkdocs-gh-pages.yaml
new file mode 100644
index 00000000..047d6b87
--- /dev/null
+++ b/.github/workflows/mkdocs-gh-pages.yaml
@@ -0,0 +1,47 @@
+name: Deploy MkDocs documentation
+
+on:
+ push:
+ branches:
+ - main
+ - f/mkdocs
+ workflow_dispatch:
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ env:
+ GH_C17_DEV_TOKEN: ${{ secrets.GH_C17_DEV_TOKEN }}
+ ENABLED_HTMLPROOFER: ${{ vars.ENABLED_HTMLPROOFER || 'False' }}
+ steps:
+ - name: Checkout reflect-cpp repo
+ uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: 3.12
+
+ - name: Install Hatch
+ uses: pypa/hatch@install
+ with:
+ version: 1.12.0
+
+ - name: Set git credentials
+ run: |
+ git config --global user.name "${{ github.actor }}"
+ git config --global user.email "${{ github.actor }}@users.noreply.github.com"
+
+ - name: Fetch latest commit from gh-pages
+ run: |
+ git fetch origin gh-pages --depth=1
+
+ - name: Deploy MkDocs documentation
+ run: hatch run insiders:mkdocs gh-deploy
+
+
+
+
+
+
+
diff --git a/.github/workflows/update-people.yml b/.github/workflows/update-people.yml
new file mode 100644
index 00000000..b561aec9
--- /dev/null
+++ b/.github/workflows/update-people.yml
@@ -0,0 +1,19 @@
+name: update-people
+
+on:
+ push:
+ branches:
+ # - f/mkdocs
+ - main
+ schedule:
+ - cron: "0 12 1 * *"
+ workflow_dispatch: {}
+
+jobs:
+ people:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: ./.github/actions/people
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 09cf71f1..d96f2b9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,29 @@
# clangd
compile_flags.txt
compile_commands.json
+
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
\ No newline at end of file
diff --git a/README.md b/README.md
index e865f4b6..489ce96f 100644
--- a/README.md
+++ b/README.md
@@ -7,24 +7,62 @@
[![Generic badge](https://img.shields.io/badge/clang-14+-blue.svg)](https://shields.io/)
[![Generic badge](https://img.shields.io/badge/MSVC-17+-blue.svg)](https://shields.io/)
+**📖 Documentation**: https://rfl.getml.com — **👨‍💻 Source Code**: https://github.com/getml/reflect-cpp
+
+> **📣 From the Author (12.11.2024):** Hi everyone, Patrick ([liuzicheng1987](https://github.com/liuzicheng1987)) here. With reflect-cpp reaching the 1k-star milestone, we’re excited to roll out an overhauled documentation site at [https://rfl.getml.com](https://rfl.getml.com/), giving it a permanent place in our company. Initially developed as an internal tool for our machine learning library, [getML](https://getml.com), reflect-cpp has grown into something much larger.
+ A big thank you to all contributors for helping us reach this point! Your feedback, ideas, and dedication have been invaluable.
+ As we look to the project’s future, I would like to hear your thoughts on potential new directions, discuss ideas to expand our user base, or learn more about what you’re building with it. For the next month, I am opening a few slots in my calendar for anyone who wants to [connect (link)](https://calendar.app.google/AaeziooCNierbwAZ8).
+ *— Best, Patrick*
+
+
+
![image](banner1.png)
**reflect-cpp** is a C++-20 library for **fast serialization, deserialization and validation** using reflection, similar to [pydantic](https://github.com/pydantic/pydantic) in Python, [serde](https://github.com/serde-rs) in Rust, [encoding](https://github.com/golang/go/tree/master/src/encoding) in Go or [aeson](https://github.com/haskell/aeson/tree/master) in Haskell.
As the aforementioned libraries are among the most widely used in the respective languages, reflect-cpp fills an important gap in C++ development. It reduces boilerplate code and increases code safety.
-Design principles for reflect-cpp include:
-- Close integration with containers from the C++ standard library
+### Design principles for reflect-cpp include:
+
+- Close integration with [containers](https://github.com/getml/reflect-cpp?tab=readme-ov-file#support-for-containers) from the C++ standard library
- Close adherence to C++ idioms
-- Out-of-the-box support for JSON
-- Simple installation
-- Simple extendability to other serialization formats
-- Simple extendability to custom classes
+- Out-of-the-box support for [JSON](https://rfl.getml.com/supported_formats/json)
+- Simple [installation](https://rfl.getml.com/install)
+- Simple extendability to [other serialization formats](https://rfl.getml.com/supported_formats/supporting_your_own_format)
+- Simple extendability to [custom classes](https://rfl.getml.com/concepts/custom_classes)
+- Being one of the fastest serialization libraries in existence, as demonstrated by our [benchmarks](https://rfl.getml.com/benchmarks)
+
+
+
+
+## Table of Contents
+
+### On this page
+ - [Serialization formats](#serialization-formats)
+ - [Feature Overview](#feature-overview)
+ - [Simple Example](#simple-example)
+ - [More Comprehensive Example](#more-comprehensive-example)
+ - [Error messages](#error-messages)
+ - [JSON schema](#json-schema)
+ - [Enums](#enums)
+ - [Algebraic data types](#algebraic-data-types)
+ - [Extra fields](#extra-fields)
+ - [Reflective programming](#reflective-programming)
+ - [Standard Library Integration](#support-for-containers)
+ - [The team behind reflect-cpp](#the-team-behind-reflect-cpp)
+ - [License](#license)
+
+### More in our [documentation](https://rfl.getml.com):
+ - [Installation ↗](https://rfl.getml.com/install/#option-2-compilation-using-cmake)
+ - [Benchmarks ↗](https://rfl.getml.com/benchmarks)
+ - [How to contribute ↗](https://rfl.getml.com/contributing)
+ - [Compiling and running the tests ↗](https://rfl.getml.com/contributing/#compiling-and-running-the-tests)
+
## Serialization formats
-reflect-cpp provides a unified reflection-based interface across different serialization formats. It is deliberately designed in a very modular way, using [concepts](https://en.cppreference.com/w/cpp/language/constraints), to make it as easy as possible to interface various C or C++ libraries related to serialization. Refer to the [documentation](https://github.com/getml/reflect-cpp/tree/main/docs) for details.
+reflect-cpp provides a unified reflection-based interface across different serialization formats. It is deliberately designed in a very modular way, using [concepts](https://en.cppreference.com/w/cpp/language/constraints), to make it as easy as possible to interface various C or C++ libraries related to serialization. Refer to the [documentation](https://rfl.getml.com/supported_formats/bson/) for details.
The following table lists the serialization formats currently supported by reflect-cpp and the underlying libraries used:
@@ -44,7 +82,10 @@ Support for more serialization formats is in development. Refer to the [issues](
Please also refer to the *vcpkg.json* in this repository.
-## Simple Example
+
+## Feature Overview
+
+### Simple Example
```cpp
#include
@@ -127,7 +168,7 @@ rfl::ubjson::read(ubjson_bytes);
rfl::xml::read(xml_string);
```
-## More Comprehensive Example
+### More Comprehensive Example
```cpp
#include
@@ -200,7 +241,7 @@ std::cout << "Hello, my name is " << homer2.first_name() << " "
<< homer2.last_name() << "." << std::endl;
```
-## Error messages
+### Error messages
reflect-cpp returns clear and comprehensive error messages:
@@ -221,7 +262,7 @@ Found 5 errors:
5) Field named 'children' not found.
```
-## JSON schema
+### JSON schema
reflect-cpp also supports generating JSON schemata:
@@ -250,7 +291,7 @@ The resulting JSON schema looks like this:
Note that this is currently supported for JSON only, since most other formats do not support schemata in the first place.
-## Enums
+### Enums
reflect-cpp supports scoped enumerations:
@@ -283,7 +324,7 @@ This results in the following JSON string:
You can also directly convert between enumerator values and strings with `rfl::enum_to_string()` and `rfl::string_to_enum()`, or
obtain list of enumerator name and value pairs with `rfl::get_enumerators()` or `rfl::get_enumerator_array()`.
-## Algebraic data types
+### Algebraic data types
reflect-cpp supports Pydantic-style tagged unions, which allow you to form algebraic data types:
@@ -314,9 +355,9 @@ This results in the following JSON string:
{"shape":"Rectangle","height":10.0,"width":5.0}
```
-Other forms of tagging are supported as well. Refer to the [documentation](https://github.com/getml/reflect-cpp/tree/main/docs) for details.
+Other forms of tagging are supported as well. Refer to the [documentation](https://rfl.getml.com/docs-readme) for details.
-## Extra fields
+### Extra fields
If you don't know all of your fields at compile time, no problem. Just use `rfl::ExtraFields`:
@@ -340,7 +381,7 @@ This results in the following JSON string:
{"firstName":"Homer","lastName":"Simpson","age":45,"email":"homer@simpson.com","town":"Springfield"}
```
-## Reflective programming
+### Reflective programming
Beyond serialization and deserialization, reflect-cpp also supports reflective programming in general.
@@ -439,9 +480,9 @@ const auto c2 = rfl::replace(c, a);
```
-## Support for containers
+### Support for containers
-### C++ standard library
+#### C++ standard library
reflect-cpp supports the following containers from the C++ standard library:
@@ -468,7 +509,7 @@ reflect-cpp supports the following containers from the C++ standard library:
- `std::vector`
- `std::wstring`
-### Additional containers
+#### Additional containers
In addition, it supports the following custom containers:
@@ -488,38 +529,10 @@ In addition, it supports the following custom containers:
- `rfl::Validator`: Allows for automatic input validation.
- `rfl::Variant`: An alternative to `std::variant` that compiles considerably faster.
-### Custom classes
-
-Finally, it is very easy to extend full support to your own classes, refer to the [documentation](https://github.com/getml/reflect-cpp/tree/main/docs) for details.
-
-## Why do we need this?
-
-Suppose your C++ program has complex data structures it needs to save and load. Or maybe it needs to interact with some kind of external API. If you do this the traditional way, you will have a lot of boilerplate code. This is annoying and error-prone.
-
-reflect-cpp is not just a reflection library, it is for **serialization, deserialization and validation** through reflection.
-
-That means that you can encode your requirements about the input data in the type system and have them validated upfront. This is why the library also includes algebraic data types like tagged unions and numerous validation routines. Having your requirements encoded in the type system is the most reliable way of ensuring they are met. If your requirements are not met, the user of your software gets a very clear error message. Encoding your requirements in the type system also makes it a lot easier for anyone reading your code.
-
-This increases user experience and developer experience, it makes your code safer (fewer bugs) and more secure (less prone to malicious attacks).
-
-For a more in-depth theoretical discussions of these topics, the following books are warmly recommended:
-
-- *Category Theory for Programmers* by Bartosz Milewski (https://github.com/hmemcpy/milewski-ctfp-pdf/releases)
-- *Domain Modeling Made Functional* by Scott Wlaschin
-
-## Documentation
+#### Custom classes
-Click [here](https://github.com/getml/reflect-cpp/tree/main/docs).
+Finally, it is very easy to extend full support to your own classes, refer to the [documentation](https://rfl.getml.com/docs-readme) for details.
-## Benchmarks
-
-reflect-cpp conducts continuuous benchmarking across different operating systems, compilers and architectures
-and publishes the results on its [Actions tab](https://github.com/getml/reflect-cpp/actions).
-Refer to the [benchmarks folder](https://github.com/getml/reflect-cpp/tree/main/benchmarks) for details.
-
-The benchmarks show that reflect-cpp is not only very convenient, but also one the fastest JSON libraries for C++.
-It is faster than RapidJSON and about 10 times faster than nlohmann/json. It can be even faster than that,
-if you choose to use a different format supported by reflect-cpp, such as msgpack.
## Installation
@@ -528,20 +541,9 @@ The following compilers are supported:
- Clang 14.0 or higher
- MSVC 17.8 (19.38) or higher
-### Option 1: Include source files into your own build
-
-Simply copy the contents of the folders `include` and `src` into your source repository or add it to your include path
-and also add `src/reflectcpp.cpp` and `src/reflectcpp_json.cpp` and `src/yyjson.c` to your source files for compilation.
-If you want to link to your own version of YYJSON, then only add `src/reflectcpp.cpp` and `src/reflectcpp_json.cpp`.
-If you don't need JSON support, then only add `src/reflectcpp.cpp`.
-
-If you need support for other serialization formats like flexbuffers or XML, you should also add `src/reflectcpp_.cpp`
-and include and link the respective libraries, as listed in the section on serialization formats.
+### Compilation using cmake
-### Option 2: Compilation using cmake
-
-This will simply compile YYJSON, which is the JSON library underlying reflect-cpp. You can then include reflect-cpp in your project and link to the binary
-to get reflect-cpp with JSON support.
+This will simply compile YYJSON, which is the JSON library underlying reflect-cpp. You can then include reflect-cpp in your project and link to the binary to get reflect-cpp with JSON support.
```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
@@ -549,122 +551,23 @@ cmake --build build -j 4 # gcc, clang
cmake --build build --config Release -j 4 # MSVC
```
-### Option 3: Compilation using cmake and vcpkg
-
-If you want serialization formats other than JSON, you can either install them manually or use vcpkg.
-
-To install vcpkg:
-
-```bash
-git submodule update --init
-./vcpkg/bootstrap-vcpkg.sh # Linux, macOS
-./vcpkg/bootstrap-vcpkg.bat # Windows
-# You may be prompted to install additional dependencies.
-```
-
-To use reflect-cpp in your project:
-
-```cmake
-add_subdirectory(reflect-cpp) # Add this project as a subdirectory
-
-set(REFLECTCPP_BSON ON) # Optional
-set(REFLECTCPP_CBOR ON) # Optional
-set(REFLECTCPP_FLEXBUFFERS ON) # Optional
-set(REFLECTCPP_MSGPACK ON) # Optional
-set(REFLECTCPP_TOML ON) # Optional
-set(REFLECTCPP_UBJSON ON) # Optional
-set(REFLECTCPP_XML ON) # Optional
-set(REFLECTCPP_YAML ON) # Optional
-
-target_link_libraries(your_project PRIVATE reflectcpp) # Link against the library
-```
-
-## Troubleshooting vcpkg
+If you need support for any other supported [serialization formats](#serialization-formats), refer to the [documentation](https://rfl.getml.com/docs-readme) for installation instructions.
-vcpkg is a great, but very ambitious and complex project (just like C++ is a great, but very ambitious and complex language). Here are some of the you might run into and how to resolve them:
+You can also [include the source files](https://rfl.getml.com/install/#option-1-include-source-files-into-your-own-build) into your build or compile it using [cmake and vcpkg.](https://rfl.getml.com/install/#option-3-compilation-using-cmake-and-vcpkg) For detailed installation instructions, please refer to the [install guide](https://rfl.getml.com/install).
-1. A lot of problems can simply be resolved by deleting the build directory using `rm -rf build`.
-2. *Environment variable VCPKG_FORCE_SYSTEM_BINARIES must be set on arm, s390x, ppc64le and riscv platforms.* - This usually happens on arm platforms like the Apple Silicon chips and can be resolved by simply preceding your build with `export VCPKG_FORCE_SYSTEM_BINARIES=arm` or `export VCPKG_FORCE_SYSTEM_BINARIES=1`.
+## The team behind reflect-cpp
-3. On some occasions you might be asked to specify a compiler. You can do so by simply adding it to the cmake command as follows: `cmake -S . -B build ... -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++` or `cmake -S . -B build ... -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17` (or whatever supported compiler you would like to use).
+reflect-cpp has been developed by [getML (Code17 GmbH)](https://getml.com), a company specializing in software engineering and machine learning for enterprise applications. reflect-cpp is currently maintained by Patrick Urbanke and Manuel Bellersen, with major contributions coming from the community.
-## Compiling and running the tests
-
-reflect-cpp uses vcpkg for dependency management, including
-gtest, which is required for the tests.
-
-```bash
-# bootstrap vcpkg if you haven't done so already
-git submodule update --init
-./vcpkg/bootstrap-vcpkg.sh # Linux, macOS
-./vcpkg/bootstrap-vcpkg.bat # Windows
-# You may be prompted to install additional dependencies.
-```
-
-### JSON only
-
-To compile the tests, do the following:
-
-```bash
-cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DREFLECTCPP_BUILD_TESTS=ON
-cmake --build build -j 4 # gcc, clang
-cmake --build build --config Release -j 4 # MSVC
-```
-
-To run the tests, do the following:
-
-```
-./build/tests/json/reflect-cpp-json-tests
-```
-
-### All serialization formats
-
-To compile the tests with serialization formats other than JSON, do the following:
-
-```bash
-cmake -S . -B build -DREFLECTCPP_BUILD_TESTS=ON -DREFLECTCPP_BSON=ON -DREFLECTCPP_CBOR=ON -DREFLECTCPP_FLEXBUFFERS=ON -DREFLECTCPP_MSGPACK=ON -DREFLECTCPP_XML=ON -DREFLECTCPP_TOML=ON -DREFLECTCPP_UBJSON=ON -DREFLECTCPP_YAML=ON -DCMAKE_BUILD_TYPE=Release
-cmake --build build -j 4 # gcc, clang
-cmake --build build --config Release -j 4 # MSVC
-```
-
-To run the tests, do the following:
-
-```
-./build/tests/bson/reflect-cpp-bson-tests
-./build/tests/cbor/reflect-cpp-cbor-tests
-./build/tests/flexbuffers/reflect-cpp-flexbuffers-tests
-./build/tests/msgpack/reflect-cpp-msgpack-tests
-./build/tests/json/reflect-cpp-json-tests
-./build/tests/toml/reflect-cpp-toml-tests
-./build/tests/ubjson/reflect-cpp-ubjson-tests
-./build/tests/xml/reflect-cpp-xml-tests
-./build/tests/yaml/reflect-cpp-yaml-tests
-```
-
-## How to contribute
-
-### Make sure includes are relative
-
-We need internal includes to be relative and not depend on any externally set include directory.
-
-That is, for example, if you are within any file in `rfl/internal`, prefer
-```cpp
-#include "to_ptr_named_tuple.hpp"
-```
-over
-```cpp
-#include "rfl/internal/to_ptr_named_tuple.hpp"
-```
-For further details and reasoning, please refer to [#30](https://github.com/getml/reflect-cpp/issues/30).
-
-## Related projects
+### Related projects
reflect-cpp was originally developed for [getml-community](https://github.com/getml/getml-community), the fastest open-source tool for feature engineering on relational data and time series. If you are interested in Data Science and/or Machine Learning, please check it out.
-## Authors
+### Professional C++ Support
+
+For comprehensive C++ support beyond the scope of GitHub discussions, we’re here to help! Reach out at [support@getml.com](mailto:support%40getml.com?subject=C++%20support%20request) to discuss any technical challenges or project requirements. We’re excited to support your work as independent software consultants.
-reflect-cpp has been developed by [scaleML](https://www.scaleml.de), a company specializing in software engineering and machine learning for enterprise applications. It is extensively used for [getML](https://getml.com), a software for automated feature engineering using relational learning.
## License
diff --git a/docs/CNAME b/docs/CNAME
new file mode 100644
index 00000000..6b9b59e9
--- /dev/null
+++ b/docs/CNAME
@@ -0,0 +1 @@
+rfl.getml.com
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
deleted file mode 100644
index e8bf2050..00000000
--- a/docs/README.md
+++ /dev/null
@@ -1,101 +0,0 @@
-# Documentation
-
-![image](banner2.png)
-
-## 1) The basics
-
-1.1) [Structs](https://github.com/getml/reflect-cpp/blob/main/docs/structs.md) - Recaps the motivating example in the README. A struct is the equivalent of an AND statement or a product type in type theory.
-
-1.2) [Optional fields](https://github.com/getml/reflect-cpp/blob/main/docs/optional_fields.md) - For defining fields in your serialized format that might be absent in some cases.
-
-1.3) [Struct flattening](https://github.com/getml/reflect-cpp/blob/main/docs/flatten_structs.md) - For making struct A "inherit" the fields of struct B.
-
-1.4) [Processors](https://github.com/getml/reflect-cpp/blob/main/docs/processors.md) - For modifying the structs before serialization and deserialization. For instance, processors can be used to transform all field names from `snake_case` to `camelCase`.
-
-1.5) [The rfl::Field-syntax](https://github.com/getml/reflect-cpp/blob/main/docs/field_syntax.md) - Describes an alternative syntax which requires slightly more effort, but allows for some powerful functionalities.
-
-1.6) [String literals](https://github.com/getml/reflect-cpp/blob/main/docs/literals.md) - For representing strings that can only assume a limited number of enumerated values.
-
-1.7) [Enums](https://github.com/getml/reflect-cpp/blob/main/docs/enums.md) - Describes how reflect-cpp handles C++ enums.
-
-1.8) [std::variant and rfl::TaggedUnion](https://github.com/getml/reflect-cpp/blob/main/docs/variants_and_tagged_unions.md) - For structs that can be one of several formats. This is the equivalent of an OR statement or a sum type in type theory.
-
-1.9) [rfl::Box and rfl::Ref](https://github.com/getml/reflect-cpp/blob/main/docs/rfl_ref.md) - For defining recursive structures.
-
-1.10) [rfl::Timestamp](https://github.com/getml/reflect-cpp/blob/main/docs/timestamps.md) - For serializing and deserializing timestamps.
-
-1.11) [rfl::Skip](https://github.com/getml/reflect-cpp/blob/main/docs/rfl_skip.md) - For skipping fields during serialization and/or deserialization.
-
-1.12) [rfl::Result](https://github.com/getml/reflect-cpp/blob/main/docs/result.md) - For error handling without exceptions.
-
-1.13) [Standard containers](https://github.com/getml/reflect-cpp/blob/main/docs/standard_containers.md) - Describes how reflect-cpp treats containers in the standard library.
-
-1.14) [C arrays and inheritance](https://github.com/getml/reflect-cpp/blob/main/docs/c_arrays_and_inheritance.md) - Describes how reflect-cpp handles C arrays and inheritance.
-
-1.15) [rfl::Bytestring](https://github.com/getml/reflect-cpp/blob/main/docs/bytestring.md) - Describes how reflect-cpp handles binary strings for formats that support them.
-
-1.16) [rfl::Binary, rfl::Hex and rfl::Oct](https://github.com/getml/reflect-cpp/blob/main/docs/number_systems.md)- For expressing numbers in different formats.
-
-## 2) Validation
-
-2.1) [Regex patterns](https://github.com/getml/reflect-cpp/blob/main/docs/patterns.md) - For requiring that strings follow used-defined regex patterns.
-
-2.2) [Validating numbers](https://github.com/getml/reflect-cpp/blob/main/docs/validating_numbers.md) - For imposing constraints on numbers.
-
-2.3) [Composing validators](https://github.com/getml/reflect-cpp/blob/main/docs/composing_validators.md) - For defining more complex validators using operators such as `rfl::AllOf` or `rfl::AnyOf`.
-
-2.4) [Size validation](https://github.com/getml/reflect-cpp/blob/main/docs/size_validation.md) - For imposing size constraints on containers such as `std::vector` or `std::string`.
-
-2.5) [JSON schema](https://github.com/getml/reflect-cpp/blob/main/docs/json_schema.md) - For validating your schema before you even send it to your C++ backend.
-
-## 3) Generic elements
-
-3.1) [rfl::Object](https://github.com/getml/reflect-cpp/blob/main/docs/object.md) - A map-like type representing a object with field names that are unknown at compile time.
-
-3.2) [rfl::Generic](https://github.com/getml/reflect-cpp/blob/main/docs/generic.md) - A catch-all type that can represent (almost) anything.
-
-3.3) [rfl::ExtraFields](https://github.com/getml/reflect-cpp/blob/main/docs/extra_fields.md) - For adding extra fields to your structs, the names of which are unknown at compile time.
-
-## 4) Custom classes
-
-4.1) [Custom classes](https://github.com/getml/reflect-cpp/blob/main/docs/custom_classes.md) - For custom classes with private fields.
-
-4.2) [Custom parsers for your classes](https://github.com/getml/reflect-cpp/blob/main/docs/custom_parser.md) - For custom classes with private fields that you want to leave absolutely untouched.
-
-## 5) Useful helper functions and classes
-
-5.1) [rfl::replace](https://github.com/getml/reflect-cpp/blob/main/docs/replace.md) - For replacing one or several fields in a struct.
-
-5.2) [rfl::as](https://github.com/getml/reflect-cpp/blob/main/docs/as.md) - For casting structs as other structs.
-
-5.3) [rfl::NamedTuple](https://github.com/getml/reflect-cpp/blob/main/docs/named_tuple.md) - For structural typing.
-
-5.4) [rfl::Tuple](https://github.com/getml/reflect-cpp/blob/main/docs/rfl_tuple.md) - An alternative to `std::tuple` that compiles more quickly.
-
-5.5) [rfl::to_view](https://github.com/getml/reflect-cpp/blob/main/docs/to_view.md) - For accessing fields of a struct by index or name.
-
-## 6) Supported formats
-
-6.1) [JSON](https://github.com/getml/reflect-cpp/blob/main/docs/json.md)
-
-6.2) [BSON](https://github.com/getml/reflect-cpp/blob/main/docs/bson.md)
-
-6.3) [CBOR](https://github.com/getml/reflect-cpp/blob/main/docs/cbor.md)
-
-6.4) [flexbuffers](https://github.com/getml/reflect-cpp/blob/main/docs/flexbuffers.md)
-
-6.5) [msgpack](https://github.com/getml/reflect-cpp/blob/main/docs/msgpack.md)
-
-6.6) [TOML](https://github.com/getml/reflect-cpp/blob/main/docs/toml.md)
-
-6.7) [UBJSON](https://github.com/getml/reflect-cpp/blob/main/docs/ubjson.md)
-
-6.8) [XML](https://github.com/getml/reflect-cpp/blob/main/docs/xml.md)
-
-6.9) [YAML](https://github.com/getml/reflect-cpp/blob/main/docs/yaml.md)
-
-## 7) Advanced topics
-
-7.1) [Supporting your own format](https://github.com/getml/reflect-cpp/blob/main/docs/supporting_your_own_format.md) - For supporting your own serialization and deserialization formats.
-
-7.2) [Maintaining backwards compatability](https://github.com/getml/reflect-cpp/blob/main/docs/backwards_compatability.md) - Instructions on how to ensure that your API is backwards-compatible with older versions.
diff --git a/docs/anonymous_fields.md b/docs/anonymous_fields.md
deleted file mode 100644
index f7db1f79..00000000
--- a/docs/anonymous_fields.md
+++ /dev/null
@@ -1,75 +0,0 @@
-# Anonymous fields
-
-If you do not want to serialize field names, you do not have to use `rfl::Field`. You can just write your struct like this:
-
-```cpp
-struct Person {
- std::string first_name;
- std::string last_name;
- std::vector children;
-};
-```
-
-This is referred to as anonymous fields. It is particularly relevant if you are using a binary format.
-
-This can be fully serialized and deserialized using `rfl::json::read` and `rfl::json::write`. No further annotations are needed.
-
-However, there are a two things you have to keep in mind:
-
-1) If you annotate *some* of the fields using either `rfl::Field`, then you must annotate *all* of them using one of these two.
-2) If you are combining structs using `rfl::Flatten`, then they structs combined like this must either be annotated or not.
-
-## Struct flattening with anonymous fields
-
-Struct flattening also works with anonymous fields:
-
-```cpp
-struct Person {
- std::string first_name;
- std::string last_name;
- int age;
-};
-
-struct Employee {
- rfl::Flatten person;
- std::string employer;
- float salary;
-};
-
-const auto employee = Employee{
- .person = Person{.first_name = "Homer",
- .last_name = "Simpson",
- .age = 45},
- .employer = "Mr. Burns",
- .salary = 60000.0};
-```
-
-This will result in the following JSON:
-
-```json
-["Homer","Simpson",45,"Mr. Burns",60000.0]
-```
-
-You can even include `std::tuple` (but `std::tuple` itself cannot contain `rfl::Flatten`):
-
-```cpp
-using Person = std::tuple;
-
-struct Employee {
- rfl::Flatten person;
- std::string employer;
- float salary;
-};
-
-const auto employee = Employee{
- .person = Person{"Homer", "Simpson", 45},
- .employer = "Mr. Burns",
- .salary = 60000.0};
-```
-
-This will result in the same JSON:
-
-```json
-["Homer","Simpson",45,"Mr. Burns",60000.0]
-```
-
diff --git a/docs/assets/images/reflectcpp.png b/docs/assets/images/reflectcpp.png
new file mode 100644
index 00000000..c1ef0015
Binary files /dev/null and b/docs/assets/images/reflectcpp.png differ
diff --git a/docs/assets/images/rfl-favicon-square.png b/docs/assets/images/rfl-favicon-square.png
new file mode 100644
index 00000000..ab5c67f5
Binary files /dev/null and b/docs/assets/images/rfl-favicon-square.png differ
diff --git a/docs/assets/images/rfl-favicon.png b/docs/assets/images/rfl-favicon.png
new file mode 100644
index 00000000..47571540
Binary files /dev/null and b/docs/assets/images/rfl-favicon.png differ
diff --git a/docs/assets/images/rfl-robot.jpg b/docs/assets/images/rfl-robot.jpg
new file mode 100644
index 00000000..fe880261
Binary files /dev/null and b/docs/assets/images/rfl-robot.jpg differ
diff --git a/docs/assets/images/rfl.png b/docs/assets/images/rfl.png
new file mode 100644
index 00000000..5b546459
Binary files /dev/null and b/docs/assets/images/rfl.png differ
diff --git a/docs/assets/stylesheets/tweaks.css b/docs/assets/stylesheets/tweaks.css
new file mode 100644
index 00000000..38fdaa74
--- /dev/null
+++ b/docs/assets/stylesheets/tweaks.css
@@ -0,0 +1,81 @@
+[data-md-color-primary=getml] {
+ --md-primary-fg-color: hsl(255 55% 60% / 1);
+ --md-primary-fg-color--light: hsl(255 47% 63% / 1);
+ --md-primary-fg-color--dark: hsl(255 52% 47% / 1);
+ --md-primary-bg-color: #fff;
+ --md-primary-bg-color--light: #ffffffb3;
+}
+
+[data-md-color-accent=getml] {
+ --md-accent-fg-color: hsl(255 100% 65% / 1);
+ --md-accent-fg-color--transparent: hsl(255.84deg 100% 65.1% / 10.2%);
+ --md-accent-bg-color: #fff;
+ --md-accent-bg-color--light: #ffffffb3;
+}
+
+[data-md-color-scheme="default"] > * {
+ --md-default-fg-color--contrast: #0e0e0e;
+}
+
+[data-md-color-scheme="slate"] > * {
+ --md-default-fg-color--contrast: #f6f6f6;
+ /* --md-default-bg-color: hsl(216deg 27.78% 7.06%); */
+}
+
+[data-md-color-scheme="slate"] {
+ --md-hue: 230;
+}
+
+.md-typeset blockquote {
+ color: var(--md-code-fg-color);
+ background-color: var(--md-code-bg-color--light);
+}
+
+/* .md-typeset h1#reflect-cpp {
+ color: var(--md-primary-bg-color);
+} */
+
+.md-typeset h1, .md-typeset h2, .md-typeset h3 {
+ color: var(--md-default-fg-color--contrast);
+ font-weight: bold;
+}
+
+.user-list {
+ display: flex;
+ flex-wrap: wrap;
+ margin-bottom: 2rem;
+}
+
+.user-list-center {
+ justify-content: space-evenly;
+}
+
+.user {
+ margin: 1em;
+ min-width: 7em;
+}
+
+.user .avatar-wrapper {
+ width: 80px;
+ height: 80px;
+ margin: 10px auto;
+ overflow: hidden;
+ border-radius: 50%;
+ position: relative;
+}
+
+.user .avatar-wrapper img {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+.user .title {
+ text-align: center;
+}
+
+.user .count {
+ font-size: 80%;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/docs/banner2.png b/docs/banner2.png
deleted file mode 100644
index 6b736f43..00000000
Binary files a/docs/banner2.png and /dev/null differ
diff --git a/docs/benchmarks.md b/docs/benchmarks.md
new file mode 100644
index 00000000..e1e25ac5
--- /dev/null
+++ b/docs/benchmarks.md
@@ -0,0 +1,9 @@
+# Benchmarks
+
+reflect-cpp conducts continuuous benchmarking across different operating systems, compilers and architectures
+and publishes the results on its [Actions tab](https://github.com/getml/reflect-cpp/actions).
+Refer to the [benchmarks folder](https://github.com/getml/reflect-cpp/tree/main/benchmarks) for details.
+
+The benchmarks show that reflect-cpp is not only very convenient, but also one the fastest JSON libraries for C++.
+It is faster than RapidJSON and about 10 times faster than nlohmann/json. It can be even faster than that,
+if you choose to use a different format supported by reflect-cpp, such as msgpack.
\ No newline at end of file
diff --git a/docs/custom_classes.md b/docs/concepts/custom_classes.md
similarity index 100%
rename from docs/custom_classes.md
rename to docs/concepts/custom_classes.md
diff --git a/docs/field_syntax.md b/docs/concepts/field_syntax.md
similarity index 100%
rename from docs/field_syntax.md
rename to docs/concepts/field_syntax.md
diff --git a/docs/processors.md b/docs/concepts/processors.md
similarity index 100%
rename from docs/processors.md
rename to docs/concepts/processors.md
diff --git a/docs/structs.md b/docs/concepts/structs.md
similarity index 90%
rename from docs/structs.md
rename to docs/concepts/structs.md
index 17c79d5b..cca07a61 100644
--- a/docs/structs.md
+++ b/docs/concepts/structs.md
@@ -82,5 +82,5 @@ Person{"Bart", "Simpson", ...};
But if you create a custom constructor, then C++ will no longer allow this kind of constructions.
If you want to create the struct from one of your classes (the most like reason, you want to create custom constructors in the first place),
-you might want to check out the section on [custom classes](https://github.com/getml/reflect-cpp/blob/main/docs/custom_classes.md) or [custom parsers](https://github.com/getml/reflect-cpp/blob/main/docs/custom_parser.md).
+you might want to check out the section on [custom classes](custom_classes.md) or [custom parsers](../custom_parser.md).
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644
index 00000000..3707d3b6
--- /dev/null
+++ b/docs/contributing.md
@@ -0,0 +1,76 @@
+---
+hide:
+ - navigation
+---
+
+# How to contribute
+
+
+## Setup
+
+Make sure includes are relative.
+
+We need internal includes to be relative and not depend on any externally set include directory.
+
+That is, for example, if you are within any file in `rfl/internal`, prefer
+```cpp
+#include "to_ptr_named_tuple.hpp"
+```
+over
+```cpp
+#include "rfl/internal/to_ptr_named_tuple.hpp"
+```
+For further details and reasoning, please refer to [#30](https://github.com/getml/reflect-cpp/issues/30).
+
+## Compiling and running the tests
+
+reflect-cpp uses vcpkg for dependency management, including
+gtest, which is required for the tests.
+
+```bash
+# bootstrap vcpkg if you haven't done so already
+git submodule update --init
+./vcpkg/bootstrap-vcpkg.sh # Linux, macOS
+./vcpkg/bootstrap-vcpkg.bat # Windows
+# You may be prompted to install additional dependencies.
+```
+
+## JSON only
+
+To compile the tests, do the following:
+
+```bash
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DREFLECTCPP_BUILD_TESTS=ON
+cmake --build build -j 4 # gcc, clang
+cmake --build build --config Release -j 4 # MSVC
+```
+
+To run the tests, do the following:
+
+```
+./build/tests/json/reflect-cpp-json-tests
+```
+
+## All serialization formats
+
+To compile the tests with serialization formats other than JSON, do the following:
+
+```bash
+cmake -S . -B build -DREFLECTCPP_BUILD_TESTS=ON -DREFLECTCPP_BSON=ON -DREFLECTCPP_CBOR=ON -DREFLECTCPP_FLEXBUFFERS=ON -DREFLECTCPP_MSGPACK=ON -DREFLECTCPP_XML=ON -DREFLECTCPP_TOML=ON -DREFLECTCPP_UBJSON=ON -DREFLECTCPP_YAML=ON -DCMAKE_BUILD_TYPE=Release
+cmake --build build -j 4 # gcc, clang
+cmake --build build --config Release -j 4 # MSVC
+```
+
+To run the tests, do the following:
+
+```
+./build/tests/bson/reflect-cpp-bson-tests
+./build/tests/cbor/reflect-cpp-cbor-tests
+./build/tests/flexbuffers/reflect-cpp-flexbuffers-tests
+./build/tests/msgpack/reflect-cpp-msgpack-tests
+./build/tests/json/reflect-cpp-json-tests
+./build/tests/toml/reflect-cpp-toml-tests
+./build/tests/ubjson/reflect-cpp-ubjson-tests
+./build/tests/xml/reflect-cpp-xml-tests
+./build/tests/yaml/reflect-cpp-yaml-tests
+```
\ No newline at end of file
diff --git a/docs/docs-readme.md b/docs/docs-readme.md
new file mode 100644
index 00000000..7ab3453f
--- /dev/null
+++ b/docs/docs-readme.md
@@ -0,0 +1,83 @@
+# Documentation
+
+## The basics
+
+[Structs](concepts/structs.md) - Recaps the motivating example in the README. A struct is the equivalent of an AND statement or a product type in type theory.
+
+[Optional fields](optional_fields.md) - For defining fields in your serialized format that might be absent in some cases.
+
+[Struct flattening](flatten_structs.md) - For making struct A "inherit" the fields of struct B.
+
+[Processors](concepts/processors.md) - For modifying the structs before serialization and deserialization. For instance, processors can be used to transform all field names from `snake_case` to `camelCase`.
+
+[The rfl::Field-syntax](concepts/field_syntax.md) - Describes an alternative syntax which requires slightly more effort, but allows for some powerful functionalities.
+
+[String literals](literals.md) - For representing strings that can only assume a limited number of enumerated values.
+
+[Enums](enums.md) - Describes how reflect-cpp handles C++ enums.
+
+[std::variant and rfl::TaggedUnion](variants_and_tagged_unions.md) - For structs that can be one of several formats. This is the equivalent of an OR statement or a sum type in type theory.
+
+[rfl::Box and rfl::Ref](rfl_ref.md) - For defining recursive structures.
+
+[rfl::Timestamp](timestamps.md) - For serializing and deserializing timestamps.
+
+[rfl::Skip](rfl_skip.md) - For skipping fields during serialization and/or deserialization.
+
+[rfl::Result](result.md) - For error handling without exceptions.
+
+[Standard containers](standard_containers.md) - Describes how reflect-cpp treats containers in the standard library.
+
+[C arrays and inheritance](c_arrays_and_inheritance.md) - Describes how reflect-cpp handles C arrays and inheritance.
+
+[rfl::Bytestring](bytestring.md) - Describes how reflect-cpp handles binary strings for formats that support them.
+
+[rfl::Binary, rfl::Hex and rfl::Oct](number_systems.md)- For expressing numbers in different formats.
+
+## Validation
+
+[Regex patterns](patterns.md) - For requiring that strings follow used-defined regex patterns.
+
+[Validating numbers](validating_numbers.md) - For imposing constraints on numbers.
+
+[Composing validators](composing_validators.md) - For defining more complex validators using operators such as `rfl::AllOf` or `rfl::AnyOf`.
+
+[Size validation](size_validation.md) - For imposing size constraints on containers such as `std::vector` or `std::string`.
+
+[JSON schema](supported_formats/json_schema.md) - For validating your schema before you even send it to your C++ backend.
+
+## Generic elements
+
+[rfl::Object](object.md) - A map-like type representing a object with field names that are unknown at compile time.
+
+[rfl::Generic](generic.md) - A catch-all type that can represent (almost) anything.
+
+[rfl::ExtraFields](extra_fields.md) - For adding extra fields to your structs, the names of which are unknown at compile time.
+
+## Custom classes
+
+[Custom classes](concepts/custom_classes.md) - For custom classes with private fields.
+
+[Custom parsers for your classes](custom_parser.md) - For custom classes with private fields that you want to leave absolutely untouched.
+
+## Useful helper functions and classes
+
+[rfl::replace](replace.md) - For replacing one or several fields in a struct.
+
+[rfl::as](as.md) - For casting structs as other structs.
+
+[rfl::NamedTuple](named_tuple.md) - For structural typing.
+
+[rfl::Tuple](rfl_tuple.md) - An alternative to `std::tuple` that compiles more quickly.
+
+[rfl::to_view](to_view.md) - For accessing fields of a struct by index or name.
+
+## Advanced topics
+
+[Supporting your own format](supported_formats/supporting_your_own_format.md) - For supporting your own serialization and deserialization formats.
+
+[Maintaining backwards compatability](backwards_compatability.md) - Instructions on how to ensure that your API is backwards-compatible with older versions.
+
+[Benchmarks](benchmarks.md) - Extensive benchmarks of popular libraries for serialization, deserialization.
+
+
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..e28e2ae5
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,86 @@
+---
+hide:
+ # - toc
+ - navigation
+ - feedback
+---
+
+
+
+
+> **📣 From the Author (01.11.2024):** Hi everyone, Patrick ([liuzicheng1987](https://github.com/liuzicheng1987)) here. With reflect-cpp reaching the 1k-star milestone, we’re excited to roll out an overhauled documentation site at [https://rfl.getml.com](https://rfl.getml.com/), giving it a permanent place in our company. Initially developed as an internal tool for our machine learning library, [getML](https://getml.com), reflect-cpp has grown into something much larger.
+ A big thank you to all contributors for helping us reach this point! Your feedback, ideas, and dedication have been invaluable.
+ As we look to the project’s future, I would like to hear your thoughts on potential new directions, discuss ideas to expand our user base, or learn more about what you’re building with it. For the next month, I am opening a few slots in my calendar for anyone who wants to [connect (link)](https://calendar.app.google/AaeziooCNierbwAZ8).
+ *— Best, Patrick*
+
+
+
+
+**reflect-cpp** is a C++-20 library for **fast serialization, deserialization and validation** using reflection, similar to [pydantic](https://github.com/pydantic/pydantic) in Python, [serde](https://github.com/serde-rs) in Rust, [encoding](https://github.com/golang/go/tree/master/src/encoding) in Go or [aeson](https://github.com/haskell/aeson/tree/master) in Haskell.
+
+reflect-cpp fills an important gap in C++ development. It minimizes boilerplate code and enhances code safety for seamless and efficient data exchange across system components.
+
+
Design principles for reflect-cpp include:
+
+- Close integration with [containers](https://github.com/getml/reflect-cpp?tab=readme-ov-file#support-for-containers) from the C++ standard library
+- Close adherence to C++ idioms
+- Out-of-the-box support for [JSON](https://rfl.getml.com/supported_formats/json)
+- Simple [installation](https://rfl.getml.com/install)
+- Simple extendability to [other serialization formats](https://rfl.getml.com/supported_formats/supporting_your_own_format)
+- Simple extendability to [custom classes](https://rfl.getml.com/concepts/custom_classes)
+- Being one of the fastest serialization libraries in existence, as demonstrated by our [benchmarks](https://rfl.getml.com/benchmarks)
+
+
+## Why do we need this?
+
+Suppose your C++ program has complex data structures it needs to save and load. Or maybe it needs to interact with some kind of external API. If you do this the traditional way, you will have a lot of boilerplate code. This is annoying and error-prone.
+
+!!! example
+
+ If you are new to reflect-cpp, please refer to our [GitHub repository](https://github.com/getml/reflect-cpp) for the latest list of supported [serialization formats]. You will also find a [simple] and [more comprehensive code example].
+
+ [github repo]: https://github.com/getml/reflect-cpp
+ [serialization formats]: https://github.com/getml/reflect-cpp#serialization-formats
+ [simple]: https://github.com/getml/reflect-cpp#simple-example
+ [more comprehensive code example]: https://github.com/getml/reflect-cpp#more-comprehensive-example
+
+
+reflect-cpp is not just a reflection library, it is for **serialization, deserialization and validation** through reflection.
+
+That means that you can encode your requirements about the input data in the type system and have them validated upfront. This is why the library also includes algebraic data types like tagged unions and numerous validation routines. Having your requirements encoded in the type system is the most reliable way of ensuring they are met. If your requirements are not met, the user of your software gets a very clear error message. Encoding your requirements in the type system also makes it a lot easier for anyone reading your code.
+
+This increases user experience and developer experience, it makes your code safer (fewer bugs) and more secure (less prone to malicious attacks).
+
+For a more in-depth theoretical discussions of these topics, the following books are warmly recommended:
+
+- *Category Theory for Programmers* by Bartosz Milewski [on GitHub](https://github.com/hmemcpy/milewski-ctfp-pdf/releases)
+- *Domain Modeling Made Functional* by Scott Wlaschin
+
+## The team behind reflect-cpp
+
+reflect-cpp has been developed by [getML (Code17 GmbH)](https://getml.com), a company specializing in software engineering and machine learning for enterprise applications. reflect-cpp is currently maintained by Patrick Urbanke and Manuel Bellersen, with major contributions coming from the community.
+
+### Related projects
+
+reflect-cpp was originally developed for [getml-community](https://github.com/getml/getml-community), the fastest open-source tool for feature engineering on relational data and time series. If you are interested in Data Science and/or Machine Learning, please check it out.
+
+### Professional C++ support
+
+For comprehensive C++ support beyond the scope of GitHub discussions, we’re here to help! Reach out at [support@getml.com](mailto:support%40getml.com?subject=C++%20support%20request) to discuss any technical challenges or project requirements. We’re excited to support your work as independent software consultants.
+
+
+## License
+reflect-cpp is released under the MIT License.
\ No newline at end of file
diff --git a/docs/install.md b/docs/install.md
new file mode 100644
index 00000000..5bdda079
--- /dev/null
+++ b/docs/install.md
@@ -0,0 +1,71 @@
+---
+hide:
+ - navigation
+---
+
+# Installation
+
+The following compilers are supported:
+- GCC 11.4 or higher
+- Clang 14.0 or higher
+- MSVC 17.8 (19.38) or higher
+
+You can include the source files into your build or compile it using cmake and vcpkg.
+
+## Option 1: Include source files into your own build
+
+Simply copy the contents of the folders `include` and `src` into your source repository or add it to your include path and also add `src/reflectcpp.cpp` and `src/reflectcpp_json.cpp` and `src/yyjson.c` to your source files for compilation.
+If you want to link to your own version of YYJSON, then only add `src/reflectcpp.cpp` and `src/reflectcpp_json.cpp`. If you don't need JSON support, then only add `src/reflectcpp.cpp`.
+
+If you need support for other serialization formats like flexbuffers or XML, you should also add `src/reflectcpp_.cpp` and include and link the respective libraries, as listed in the section on serialization formats.
+
+## Option 2: Compilation using cmake
+
+This will simply compile YYJSON, which is the JSON library underlying reflect-cpp. You can then include reflect-cpp in your project and link to the binary
+to get reflect-cpp with JSON support.
+
+```bash
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
+cmake --build build -j 4 # gcc, clang
+cmake --build build --config Release -j 4 # MSVC
+```
+
+## Option 3: Compilation using cmake and vcpkg
+
+If you want serialization formats other than JSON, you can either install them manually or use vcpkg.
+
+To install vcpkg:
+
+```bash
+git submodule update --init
+./vcpkg/bootstrap-vcpkg.sh # Linux, macOS
+./vcpkg/bootstrap-vcpkg.bat # Windows
+# You may be prompted to install additional dependencies.
+```
+
+To use reflect-cpp in your project:
+
+```cmake
+add_subdirectory(reflect-cpp) # Add this project as a subdirectory
+
+set(REFLECTCPP_BSON ON) # Optional
+set(REFLECTCPP_CBOR ON) # Optional
+set(REFLECTCPP_FLEXBUFFERS ON) # Optional
+set(REFLECTCPP_MSGPACK ON) # Optional
+set(REFLECTCPP_TOML ON) # Optional
+set(REFLECTCPP_UBJSON ON) # Optional
+set(REFLECTCPP_XML ON) # Optional
+set(REFLECTCPP_YAML ON) # Optional
+
+target_link_libraries(your_project PRIVATE reflectcpp) # Link against the library
+```
+
+## Troubleshooting vcpkg
+
+vcpkg is a great, but very ambitious and complex project (just like C++ is a great, but very ambitious and complex language). Here are some of the you might run into and how to resolve them:
+
+1. A lot of problems can simply be resolved by deleting the build directory using `rm -rf build`.
+
+2. *Environment variable VCPKG_FORCE_SYSTEM_BINARIES must be set on arm, s390x, ppc64le and riscv platforms.* - This usually happens on arm platforms like the Apple Silicon chips and can be resolved by simply preceding your build with `export VCPKG_FORCE_SYSTEM_BINARIES=arm` or `export VCPKG_FORCE_SYSTEM_BINARIES=1`.
+
+3. On some occasions you might be asked to specify a compiler. You can do so by simply adding it to the cmake command as follows: `cmake -S . -B build ... -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++` or `cmake -S . -B build ... -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17` (or whatever supported compiler you would like to use).
\ No newline at end of file
diff --git a/docs/people.md b/docs/people.md
new file mode 100644
index 00000000..e165d3bc
--- /dev/null
+++ b/docs/people.md
@@ -0,0 +1,34 @@
+---
+hide:
+ - navigation
+---
+
+
+# People
+
+reflect-cpp is supported by a group of contributors and reviewers who help improve the project constantly. This page is dedicated to recognizing their efforts and contributions.
+
+## Maintainers
+
+The following people maintain the reflect-cpp repository on behalf of the Code17 GmbH. The main author of the library is Dr. Patrick Urbanke ([@liuzicheng1987](https://github.com/liuzicheng1987)).
+
+{{ maintainers }}
+
+## Contributors
+
+Here are the users who have contributed with the pull requests that were successfully merged.
+
+{{ top_contributors }}
+
+## Reviewers
+
+These users have reviewed pull requests from others, improving code quality, fixing bugs, and more.
+
+{{ top_reviewers }}
+
+## About the data
+
+The information shown above is updated monthly using the Github GraphQL API.
+
+You can find the source code for generating this data [here](https://github.com/getml/reflect-cpp/tree/main/.github/actions/people/people.py). The code is borrowed from the [pydantic project](https://github.com/pydantic/pydantic/blob/main/.github/actions/people/people.py), and modified to work with the reflect-cpp repository. Originally, the logic comes from [FastAPI](https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py).
+
diff --git a/docs/plugins/main.py b/docs/plugins/main.py
new file mode 100644
index 00000000..475eced1
--- /dev/null
+++ b/docs/plugins/main.py
@@ -0,0 +1,133 @@
+from pathlib import Path
+import re
+from jinja2 import Template
+from mkdocs.config import Config
+
+from mkdocs.structure.files import Files
+from mkdocs.structure.pages import Page
+import yaml
+
+THIS_DIR = Path(__file__).parent
+
+
+def on_page_markdown(markdown: str, page: Page, config: Config, files: Files) -> str:
+ """
+ Called on each file after it is read and before it is converted to HTML.
+ """
+
+ if md := populate_people(markdown, page):
+ return md
+ return markdown
+
+
+experts_template = Template(
+ """
+