1
0

4 Commits

Author SHA1 Message Date
ab8489c377 doc: add doc for moved files 2025-10-07 18:49:02 +08:00
c48e79753d refactor: cancel the namespace Rust.
- all sub-functions are put into respective position.
2025-10-07 18:15:17 +08:00
eda801d3c7 refactor: move env outside from rust namespace 2025-10-07 18:03:40 +08:00
64045b1d48 doc: update license date 2025-10-03 22:52:31 +08:00
27 changed files with 183 additions and 139 deletions

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2024-2024 yyc12345
Copyright (c) 2024-2025 yyc12345
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -29,7 +29,7 @@ In short words, this library use UTF8 encoding everywhere except some special ca
\li Traditional format function in yycc::string::op.
Traditional format function provide some overloads for ordinary string formatting.
That's because this feature is so common to use in some cases.
\li The message of Rust panic in yycc::rust::panic.
\li The message of Rust panic in yycc::panic.
Due to the limitation of \c std::format, we only can use ordinary string as its message content.
\li The message of standard library exception.
For the compatibility with C++ standard library exception,

View File

@ -15,8 +15,8 @@ PRIVATE
yycc/string/op.cpp
yycc/patch/fopen.cpp
yycc/patch/stream.cpp
yycc/rust/panic.cpp
yycc/rust/env.cpp
yycc/panic.cpp
yycc/env.cpp
yycc/windows/com.cpp
yycc/windows/dialog.cpp
yycc/windows/winfct.cpp
@ -53,6 +53,7 @@ FILES
yycc/macro/class_copy_move.hpp
yycc/macro/printf_checker.hpp
yycc/flag_enum.hpp
yycc/string.hpp
yycc/string/reinterpret.hpp
yycc/string/op.hpp
yycc/patch/ptr_pad.hpp
@ -64,12 +65,12 @@ FILES
yycc/num/safe_cast.hpp
yycc/num/safe_op.hpp
yycc/num/op.hpp
yycc/rust/prelude.hpp
yycc/rust/primitive.hpp
yycc/rust/panic.hpp
yycc/rust/option.hpp
yycc/rust/result.hpp
yycc/rust/env.hpp
yycc/primitive.hpp
yycc/option.hpp
yycc/result.hpp
yycc/prelude.hpp
yycc/panic.hpp
yycc/env.hpp
yycc/windows/import_guard_head.hpp
yycc/windows/import_guard_tail.hpp
yycc/windows/com.hpp

View File

@ -3,7 +3,7 @@
#include "../../patch/stream.hpp"
#include "../../patch/format.hpp"
#include "../../string/op.hpp"
#include "../../rust/env.hpp"
#include "../../env.hpp"
#include <ranges>
#define CLAP ::yycc::carton::clap
@ -11,7 +11,7 @@
#define TERMCOLOR ::yycc::carton::termcolor
#define OP ::yycc::string::op
#define FORMAT ::yycc::patch::format
#define ENV ::yycc::rust::env
#define ENV ::yycc::env
using namespace ::yycc::patch::stream;

View File

@ -1,15 +1,15 @@
#include "env.hpp"
#include "../macro/os_detector.hpp"
#include "macro/os_detector.hpp"
// Environment variable required
#if defined(YYCC_OS_WINDOWS)
#include "../encoding/windows.hpp"
#include "../num/safe_op.hpp"
#include "../num/safe_cast.hpp"
#include "encoding/windows.hpp"
#include "num/safe_op.hpp"
#include "num/safe_cast.hpp"
#include <Windows.h>
#include <winbase.h>
#else
#include "../string/reinterpret.hpp"
#include "string/reinterpret.hpp"
#include <cstdlib>
#include <cerrno>
#include <stdexcept>
@ -17,7 +17,7 @@
// Path related functions required
#if defined(YYCC_OS_WINDOWS)
#include "../windows/winfct.hpp"
#include "windows/winfct.hpp"
#else
#include <unistd.h>
#include <sys/stat.h>
@ -29,7 +29,7 @@
#define REINTERPRET ::yycc::string::reinterpret
#define WINFCT ::yycc::windows::winfct
namespace yycc::rust::env {
namespace yycc::env {
#pragma region Environment Variable
@ -207,4 +207,4 @@ namespace yycc::rust::env {
#pragma endregion
} // namespace yycc::rust::env
} // namespace yycc::env

View File

@ -4,17 +4,17 @@
#include <expected>
/**
* @brief The namespace providing environment variable operations.
* @brief The namespace providing runtime environment operations.
* @details
* When I programming with Rust, I was astonished that
* Rust standard library have so much robust environment variable operations.
* Oppositly, C++ STL still lake in this even in today.
*
* The functions manipulating environment variable is different in different OS.
* I create this namespace inspired from Rust standard library
* to glue all these things up and make a uniform interface.
* Rust standard library have so much robust environment-related operations,
* such as environment variable operations, current program infos and etc.
* Oppositly, C++ STL are still lack in this even in today.
* So I create this namespace to glue all these things up,
* according to different operating systems, and make a uniform interface.
*/
namespace yycc::rust::env {
namespace yycc::env {
#pragma region Environment Variable
@ -86,4 +86,4 @@ namespace yycc::rust::env {
#pragma endregion
} // namespace yycc::rust::env
} // namespace yycc::env

View File

@ -7,7 +7,7 @@
* This namespace reproduce Rust Option type, and its members Some and None in C++.
* However Option is not important than Result, so its implementation is very casual.
*/
namespace yycc::rust::option {
namespace yycc::option {
template<typename T>
using Option = std::optional<T>;
@ -22,4 +22,4 @@ namespace yycc::rust::option {
return OptionType(std::nullopt);
}
} // namespace yycc::rust::option
} // namespace yycc::option

View File

@ -1,6 +1,6 @@
#include "panic.hpp"
#include "../carton/termcolor.hpp"
#include "../patch/stream.hpp"
#include "carton/termcolor.hpp"
#include "patch/stream.hpp"
#include <cstdlib>
#include <iomanip>
#include <iostream>
@ -10,7 +10,7 @@
using namespace yycc::patch::stream;
namespace yycc::rust::panic {
namespace yycc::panic {
void panic(const char* file, int line, const std::u8string_view& msg) {
// Output message in stderr.
@ -36,4 +36,4 @@ namespace yycc::rust::panic {
std::abort();
}
} // namespace yycc::rust::panic
} // namespace yycc::panic

View File

@ -1,5 +1,5 @@
#pragma once
#include "../patch/format.hpp"
#include "patch/format.hpp"
#include <string_view>
#include <format>
@ -15,13 +15,16 @@
*
* Unfortunately, I cannot change the exception mechanism in the standard library.
* The standard library will still throw exceptions where it does, and I cannot prevent that.
* Therefore, I suggest a good practice that any C++ exception should be immediately treated as an error and cause the program to crash and exit.
* For this reason, registering any unhandled error callbacks which may resume the execution of program is prohibited to prevent unexpected continuation of execution.
* For code we write ourselves that we can control, we should use the macros provided in this file instead of throwing exceptions.
* In this way, unexpected behavior in our code will cause the program to exit immediately, outputting error information and stack traces.
* Therefore, I suggest a good practice call "exception is error",
* any C++ exception should be immediately treated as an error and cause the program to crash and exit.
* For this reason, registering any unhandled error callbacks which may resume the execution of program
* is strictly prohibited to prevent any unexpected recovery from exceptions.
* For code your written, you should use the macros provided in this file instead of throwing exceptions.
* In this way, unexpected behavior in code will cause immediate exit, shown error information and stack traces.
* Standard library exceptions will also cause the program to exit, but without stack information.
* However, if you are following "exception is error" rule, you still can throw exceptions instead.
*/
namespace yycc::rust::panic {
namespace yycc::panic {
/**
* @brief Immediately crashes the entire program like Rust's \c panic! macro.
@ -31,7 +34,7 @@ namespace yycc::rust::panic {
* However, this format function is specially modified that it can accept UTF8 format string and UTF8 string argument.
* More preciously, it is "format" in \c yycc::patch::format namespace.
*/
#define RS_PANIC(msg, ...) ::yycc::rust::panic::panic(__FILE__, __LINE__, ::yycc::patch::format::format(msg __VA_OPT__(, ) __VA_ARGS__))
#define RS_PANIC(msg, ...) ::yycc::panic::panic(__FILE__, __LINE__, ::yycc::patch::format::format(msg __VA_OPT__(, ) __VA_ARGS__))
/**
* @brief Immediately crashes the entire program like Rust's \c panic! macro.
@ -44,4 +47,4 @@ namespace yycc::rust::panic {
*/
[[noreturn]] void panic(const char* file, int line, const std::u8string_view& msg);
} // namespace yycc::rust::panic
} // namespace yycc::panic

68
src/yycc/prelude.hpp Normal file
View File

@ -0,0 +1,68 @@
#pragma once
/**
* @file
* @brief The Rust-like prelude header for C++.
* @details
* When I writting with Rust, I notice Rust add types for all files in default.
* This default imported types are called "prelude".
* This is very convenient for programming so I decide to introduce it in C++.
*
* I create this file, organize all types, which I think should be exposed for programmer, in to an independent namespace,
* and expose them into global namesoace.
* By simply include this file at the top of your C++ code, you can get Rust-like prelude effect in C++.
* These exposed types including primitive types, string types, basic Option and Result utilities, panic mechanisim and etc.
*/
// Rust prelude section
#include "primitive.hpp"
#include "result.hpp"
#include "option.hpp"
#include "panic.hpp"
#include <vector>
/**
* @brief The namespace including all types presented in prelude.
* @details
* By including this file, all of these types are automaticalling exposed to global namespace.
* There is no need to refer this namespace anymore.
* This namespace is just a container for types which need to be exposed.
*/
namespace yycc::prelude {
// Include primitive types
#define NS_YYCC_PRIMITIVE ::yycc::primitive
using i8 = NS_YYCC_PRIMITIVE::i8;
using i16 = NS_YYCC_PRIMITIVE::i16;
using i32 = NS_YYCC_PRIMITIVE::i32;
using i64 = NS_YYCC_PRIMITIVE::i64;
using u8 = NS_YYCC_PRIMITIVE::u8;
using u16 = NS_YYCC_PRIMITIVE::u16;
using u32 = NS_YYCC_PRIMITIVE::u32;
using u64 = NS_YYCC_PRIMITIVE::u64;
using isize = NS_YYCC_PRIMITIVE::isize;
using usize = NS_YYCC_PRIMITIVE::usize;
using f32 = NS_YYCC_PRIMITIVE::f32;
using f64 = NS_YYCC_PRIMITIVE::f64;
#undef NS_YYCC_PRIMITIVE
// Other types
//using str = std::u8string_view;
//using String = std::u8string;
template<typename T>
using Vec = std::vector<T>;
// Expose Result and Option
using namespace ::yycc::option;
using namespace ::yycc::result;
// Panic are introduced by including header file
// so we do not need re-expose it.
} // namespace yycc::prelude
// Expose all members
using namespace ::yycc::prelude;

40
src/yycc/primitive.hpp Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <string_view>
/**
* @brief The namespace providing primitive types.
* @details
* When I writing with Rust, I notice that most pf primitive types has explicit and exact size, and their names are short and clear.
* Hoeever, in C++, most primitive types are variable based on system, due to the legacy of C era.
* All primitive types with explicit size are only can be fetched in a specific header file,
* and, their names are too long because they can not be registered as reserved keywords or names
* due to the name conflict with so much code written in past years.
* However, STL can't do this but I can do this.
* I invent this namespace providing primitive types, such as integers, floating-point numbers, and strings,
* in Rust style, their names areshort and clear.
*/
namespace yycc::primitive {
// `bool` is keyword so should not declare it anymore.
// `char` is keyword so should not declare it anymore.
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using isize = std::ptrdiff_t;
using usize = std::size_t;
using f32 = float;
using f64 = double;
// using String = std::u8string;
// using str = std::u8string_view;
}

View File

@ -36,7 +36,7 @@
* Similarly, when using \c std::cerr 's \c operator<< overload, you also need to write suitable adapters.
* @remarks This namespace only work with environment supporting `std::expected` (i.e. C++ 23).
*/
namespace yycc::rust::result {
namespace yycc::result {
/**
* @brief Equivalent Rust \c Result in C++
@ -74,4 +74,4 @@ namespace yycc::rust::result {
return ResultType(std::unexpect, std::forward<Args>(args)...);
}
} // namespace yycc::rust::result
} // namespace yycc::result

View File

@ -1,49 +0,0 @@
#pragma once
// Rust prelude section
#include "primitive.hpp"
#include "result.hpp"
#include "option.hpp"
#include "panic.hpp"
#include <vector>
namespace yycc::rust::prelude {
// Include primitive types
#define NS_RUST_PRIMITIVE ::yycc::rust::primitive
using i8 = NS_RUST_PRIMITIVE::i8;
using i16 = NS_RUST_PRIMITIVE::i16;
using i32 = NS_RUST_PRIMITIVE::i32;
using i64 = NS_RUST_PRIMITIVE::i64;
using u8 = NS_RUST_PRIMITIVE::u8;
using u16 = NS_RUST_PRIMITIVE::u16;
using u32 = NS_RUST_PRIMITIVE::u32;
using u64 = NS_RUST_PRIMITIVE::u64;
using isize = NS_RUST_PRIMITIVE::isize;
using usize = NS_RUST_PRIMITIVE::usize;
using f32 = NS_RUST_PRIMITIVE::f32;
using f64 = NS_RUST_PRIMITIVE::f64;
using str = NS_RUST_PRIMITIVE::str;
#undef NS_RUST_PRIMITIVE
// Other types
using String = std::u8string;
template<typename T>
using Vec = std::vector<T>;
// Expose Result and Option
using namespace ::yycc::rust::option;
using namespace ::yycc::rust::result;
// Panic are introduced by including header file
// so we do not need re-expose it.
} // namespace yycc::prelude::rust
// Expose all members
using namespace ::yycc::rust::prelude;

View File

@ -1,28 +0,0 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <string_view>
namespace yycc::rust::primitive {
// `bool` is keyword so should not declare it anymore.
// `char` is keyword so should not declare it anymore.
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using isize = std::ptrdiff_t;
using usize = std::size_t;
using f32 = float;
using f64 = double;
using str = std::u8string_view;
}

9
src/yycc/string.hpp Normal file
View File

@ -0,0 +1,9 @@
#pragma once
// TODO:
// Add content safe, Rust-like string container "String"
// and string view "str" in there.
// Once we add it, all string process function can be migrated as their class member,
// or keep them independendly but change the type of parameter into our string types.
namespace yycc::string {}

View File

@ -20,7 +20,7 @@ PRIVATE
yycc/patch/fopen.cpp
yycc/patch/stream.cpp
yycc/patch/format.cpp
yycc/rust/env.cpp
yycc/env.cpp
yycc/string/reinterpret.cpp
yycc/string/op.cpp
yycc/num/parse.cpp

View File

@ -2,7 +2,7 @@
#include <yycc.hpp>
#include <yycc/constraint.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define CONSTRAINT ::yycc::constraint::Constraint

View File

@ -2,7 +2,7 @@
#include <yycc.hpp>
#include <yycc/constraint/builder.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define BUILDER ::yycc::constraint::builder
using namespace std::literals::string_view_literals;

View File

@ -1,17 +1,17 @@
#include <gtest/gtest.h>
#include <yycc.hpp>
#include <yycc/rust/env.hpp>
#include <yycc/env.hpp>
#include <yycc/macro/os_detector.hpp>
#include <filesystem>
#define ENV ::yycc::rust::env
#define ENV ::yycc::env
namespace yycctest::rust::env {
namespace yycctest::env {
constexpr char8_t VAR_NAME[] = u8"HOMER";
constexpr char8_t VAR_VALUE[] = u8"doh";
TEST(RustEnv, EnvVar) {
TEST(Env, EnvVar) {
// Write a new variable should okey
{
auto rv = ENV::set_var(VAR_NAME, VAR_VALUE);
@ -44,7 +44,7 @@ namespace yycctest::rust::env {
}
}
TEST(RustEnv, CurrentExe) {
TEST(Env, CurrentExe) {
auto rv = ENV::current_exe();
ASSERT_TRUE(rv.has_value());
@ -59,4 +59,4 @@ namespace yycctest::rust::env {
#endif
}
} // namespace yycctest::rust::env
} // namespace yycctest::env

View File

@ -3,7 +3,7 @@
#include <yycc/flag_enum.hpp>
#include <cinttypes>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define FLAG_ENUM ::yycc::flag_enum

View File

@ -2,7 +2,7 @@
#include <yycc.hpp>
#include <yycc/num/op.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define OP ::yycc::num::op

View File

@ -2,7 +2,7 @@
#include <yycc.hpp>
#include <yycc/num/parse.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define PARSE ::yycc::num::parse

View File

@ -3,7 +3,7 @@
#include <yycc/num/safe_cast.hpp>
#include <yycc/macro/ptr_size_detector.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define CAST ::yycc::num::safe_cast

View File

@ -4,7 +4,7 @@
#include <cstdint>
#include <limits>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define OP ::yycc::num::safe_op

View File

@ -2,7 +2,7 @@
#include <yycc.hpp>
#include <yycc/num/stringify.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define STRINGIFY ::yycc::num::stringify

View File

@ -2,7 +2,7 @@
#include <yycc.hpp>
#include <yycc/string/op.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define OP ::yycc::string::op
using namespace std::literals::string_view_literals;

View File

@ -3,7 +3,7 @@
#include <yycc.hpp>
#include <yycc/string/reinterpret.hpp>
#include <yycc/rust/prelude.hpp>
#include <yycc/prelude.hpp>
#define REINTERPRET ::yycc::string::reinterpret
#define AS_UINT8(p) static_cast<u8>(p)