diff --git a/.ci/ci b/.ci/ci index 47678769f..e982e8e74 100755 --- a/.ci/ci +++ b/.ci/ci @@ -59,6 +59,7 @@ make -j8 bootloader-btc-production make -j8 firmware make -j8 firmware-btc make -j8 factory-setup +make -j8 firmware-debug # Disallow some symbols in the final binary that we don't want. if arm-none-eabi-nm build/bin/firmware.elf | grep -q "float_to_decimal_common_shortest"; then diff --git a/BUILD.md b/BUILD.md index 67f6f8508..0c246e9e5 100644 --- a/BUILD.md +++ b/BUILD.md @@ -2,21 +2,6 @@ # Build BitBox02 firmware and bootloader -## Dependencies - -- [HIDAPI](https://github.com/signal11/hidapi) -- [GNU ARM Embedded Toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) -- SEGGER J-Link software - - [All packages and versions](https://www.segger.com/downloads/jlink/#J-LinkSoftwareAndDocumentationPack) - - Newer versions should work, but if not, go to "Older versions" and get version 6.34g - - [OSX package](https://www.segger.com/downloads/jlink/JLink_MacOSX_V630d.pkg) - - [Linux 64bit](https://www.segger.com/downloads/jlink/JLink_Linux_x86_64.tgz) - - [others](https://www.segger.com/downloads/jlink/) -- cmake -- git -- Install the pre-built [protobuf python binary](https://github.com/protocolbuffers/protobuf/releases) - - Then install the included [Python Protocol Buffers](https://github.com/protocolbuffers/protobuf/tree/master/python#installation) runtime library - ## Reporting issues @@ -25,129 +10,218 @@ For security related issues please see [SECURITY.md](SECURITY.md). ## Development environment -### Install development environment as a Docker container +There is a container image with all the build dependencies and there are some +`make` shortcuts to use it. -The container will contain all tools needed to build the project but it is still necessary to get -the J-Link software to flash the bootloader. Run the commands below to build the container and -execute a persistent one. +> [!TIP] +> It is highly recommended to use the container for development. -```sh -make dockerinit -make dockerdev -``` +Accessing USB devices, like the flashing tool and the bitbox, is easier outside +of the container. So it is recommended to install the J-Link Software on your +development machine to follow the instructions below. + +### Development Dependencies* + +| Dependency | Version** | +| ---------- | -------- | +| [Arm GNU Toolchain](https://developer.arm.com/downloads/-/gnu-rm) | 8-2018-q4 | +| [HIDAPI](https://github.com/signal11/hidapi) | 0.11.2 | +| [cmake](https://cmake.org/download/) | 3.10 | +| [git](https://git-scm.com/downloads) | 2.34 | +| [Protobuf Compiler](https://github.com/protocolbuffers/protobuf/releases) | 21.2 | +| [Python Probobuf Runtime](https://github.com/protocolbuffers/protobuf/tree/master/python#installation) | 5.27.3 | +| [SEGGER J-Link Software and Documentation Pack](https://www.segger.com/downloads/jlink) | 6.34g | +| Graphviz | 2.42.2 | +| Doxygen | 1.9.1 | +| [cmocka](https://cmocka.org/files/1.1/) | 1.1.5 | -If you do not want to build the docker image locally, or are not working on it, it may be more straightforward to -pull the image from docker instead of building it. This should be a bit faster and there should not be any issues with -`make dockerdev` expecting specific version of the image. +* See the complete list of dependences in the Dockerfile. + +** The versions here are known to be working. Newer versions should +work. + +### Setup containerized environment + +Run the following commands to fetch the container image and run it: ```sh make dockerpull make dockerdev ``` +`dockerpull` will use `docker pull` to fetch the current container image. +`dockerdev` will use `docker run` and `docker exec` to run a container in the +background and enter it. `dockerdev` will mount the project root using the same +path inside the container, which lets you use your preferred editor/IDE outside +the container. -The docker container will not allow you to access the hosts USB devices by default which means that -it is necessary to flash the device in a terminal not running in docker. +> [!NOTE] +> The current development container is defined in +> [.containerversion](.containerversion). This is the version that is pulled +> with `dockerpull` and built with `dockerinit`. > [!NOTE] -> Current development container is defined in the file `.containerversion` +> `make dockerdev` will enter an already running container if it exists. -The docker container mounts the repo it was launched from, so you can freely edit your fork in your preferred IDE and -the changes will be reflected in the docker container. +Run the following command to build the container: -**It is highly recommended you develop using this docker container as not all of local setup is completely up to date -with every Operating system.** +```sh +make dockerinit +``` + +`dockerinit` is a shortcut to run `docker build`. Use this if you need to +permanently update the container image ([Dockerfile](Dockerfile)). Don't forget +to update the [container version file](.containerversion). + +> [!TIP] +> For temporary changes you should enter the container running `docker exec` +> with user id 0. -### Install development environment on macOS +### Setup development environment on macOS with brew -Make sure you have [Homebrew](https://brew.sh) installed. -Install the dependencies with: +> [!CAUTION] +> Brew usually only supports the latest versions of software packages. It is +> not easy to get a working development environment using brew. Any +> discrepancies between your environment and the containerized environment may +> lead to CI build failures, since CI uses the container. + +> [!IMPORTANT] +> If you use compiler versions different from CI you will not be able to +> reproducibly build the firmware. Different compilers typically lead to +> slightly different binary outputs. + +Make sure you have [Homebrew](https://brew.sh) installed. Install the +dependencies with: ```sh -brew install hidapi cmake protobuf -brew install automake libtool # for building some code in the external/ folder +brew install hidapi cmake protobuf@21 +brew install automake libtool brew tap osx-cross/arm brew install arm-gcc-bin ``` -## Simulator - -The Multi edition firmware can be built as a simulator for linux-amd64. To build it, run: - - make -j simulator +## Contributor instructions -Run it with: +### Check out the repository - ./build-build/bin/simulator +#### 1. Fork the repository on github. -This launches a server simulating the firmware. The send_message tool can connect to it with: +Go to [bitbox02-firmware](https://github.com/bitboxswiss/bitbox02-firmware) and fork the repository. - ./py/send_message.py --simulator +#### 2. Check out your fork -If you choose to create a wallet by restoring a mnemonic, the simulator will automatically use this -mnemonic: +Run the following commands to check out your fork: - boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide +```sh +git clone --recurse-submodules git@github.com:/bitbox02-firmware.git +cd bitbox02-firmware +``` -## Instructions +> [!TIP] +> If you have already cloned the repository without the `--recurse-submodules` +> argument, run: +> +> ```sh +> git submodule update --init --recursive +> ``` -Connect the J-Link to the debug pins on the BitBox02 prototype board. +> [!TIP] +> Add the original repo as a second remote so that you can sync the `master` branch. +> ``` +> git remote add upstream https://github.com/bitboxswiss/bitbox02-firmware +> ``` -Plug in both the J-Link hardware and the BitBox02 device into USB ports on your computer or a hub connected to your computer. +### Build the firmware -Build the firmware: +Run the following commands to enter the container and build the firmware: ```sh -git clone --recurse-submodules https://github.com/BitBoxSwiss/bitbox02-firmware && cd bitbox02-firmware -# or via ssh -git clone --recurse-submodules git@github.com:BitBoxSwiss/bitbox02-firmware.git && cd bitbox02-firmware -make firmware # requires a GNU ARM toolchain for cross-compiling +make dockerdev +make firmware ``` -If you have already cloned the repository without the `--recurse-submodules` argument, run: +> [!TIP] +> If you have multiple cores you can speed up compilation by passing `-j`, for example `-j8`. -```sh -git submodule update --init --recursive -``` +### Build the bootloader -Build the bootloader: +Run the following commands to enter the container and build the bootloader: ```sh +make dockerdev make bootloader ``` -(to create a bootloader for a devdevice or a production device, use `make bootloader-devdevice` or -`make bootloader-production` respectively). +> [!NOTE] +> To create a bootloader for a development or a production device, use `make +> bootloader-devdevice` or `make bootloader-production` respectively. + +> [!NOTE] +> To run unsigned firmwares you need a development bootloader. + +### Build the simulator -Load the bootloader by JLink (requires JLinkExe in PATH). +The Multi edition firmware can be built as a simulator for linux-amd64. To build it, run: ```sh -make jlink-flash-bootloader +make simulator ``` -You need to install the [BitBox02 Python Library](#BitBox02-Python-library) before you can flash the built firmware. +### Flash instructions + +#### Connect J-Link probe + +Connect the J-Link probe to the debug pins on the BitBox02 prototype board. The +pinout of the board and the Arm JTAG/SWD 10-pin connector can be seen in the +table below. + +| Signal | Bitbox02 # | Arm JTAG/SWD # | +| ------ | ---------- | -------------- | +| VCC | 1 | 1 | +| CLK | 2 | 4 | +| GND | 3 | 3, 5 | +| DIO | 4 | 2 | + +See [bitbox schematics](doc/bb02_v2.10_schematics.pdf) and [Arm JTAG/SWD +interface](https://developer.arm.com/documentation/101636/0100/Debug-and-Trace/JTAG-SWD-Interface) + +Plug **both** the J-Link probe and the BitBox02 into the computer using USB. A +USB hub can be used. -Load the firmware by the bootloader (requires loading bootloader.bin by JLink, if not already loaded on the device): +#### Flash bootloader using J-Link + +Load the bootloader by JLink (requires `JLinkExe` in `$PATH`). ```sh -make flash-dev-firmware +make jlink-flash-bootloader ``` +> [!NOTE] +> To flash a bootloader for a development device +> `make jlink-flash-bootloader-development`. + +#### Flash firmware using J-Link + Load the firmware by JLink: ```sh make jlink-flash-firmware ``` -### Build reference documentation (Doxygen) +#### Flash firmware using bootloader and python cli client + +> [!TIP] +> This method does not require a J-Link probe while developing. -Dependencies: +Install the [BitBox02 Python CLI client](#bitbox02-python-cli-client). + +Load the firmware through the bootloader: ```sh -brew install graphviz doxygen +make flash-dev-firmware ``` -Build: +### Build reference documentation (Doxygen) ```sh make docs @@ -155,48 +229,106 @@ make docs To view the results, open `build/docs/html/index.html` in a web browser. -### BitBox02 Python library +### Debugging -There is a Python api library in `py/bitbox02`. +#### Debugging using the simulator -Run `pip install -r py/requirements.txt` to install the deps (virtualenv recommended). - -`make -C py/bitbox02` to generate the protobuf files. - -To kick off some api calls: +Run it with: ```sh -./py/send_message.py +./build-build/bin/simulator ``` -### Unit tests +This launches a server simulating the firmware. The send_message tool can connect to it with: + + ./py/send_message.py --simulator + +If you choose to create a wallet by restoring a mnemonic, the simulator will automatically use this +mnemonic: + + boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide + + +#### Debugging using the J-Link probe and GDB + +The *debug firmware* enables pretty printing of panics over [RTT](https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/). -We are using CMocka [https://cmocka.org/](https://cmocka.org/) for unit tests. To run the tests, the CMocka library -needs to be installed on your system. +Run the following commands to build the debug firmware. -If you're on a Mac, you can use the brew command to install it: +```sh +make dockerdev +make firmware-debug +``` + +Run the following command to run the J-Link GDB Server. ```sh -brew install cmocka +make jlink-gdb-server ``` -Alternatively, you can get CMocka by cloning the git repository and following these instructions: +> [!IMPORTANT] +> The J-Link GDB Server must be left running in the background. + +Run the following command to connect with telnet to the J-Link GDB Server to +see the RTT output. ```sh -git clone git://git.cryptomilk.org/projects/cmocka.git -cd cmocka -mkdir build && cd build -cmake .. -make && sudo make install +make rtt-client ``` -By default, the library will be installed into /usr/local/lib64 directory under Linux x86\_64. -If the library is not on the library path by default, you might need to export the following environment variable: +Run the following command to run GDB. GDB will connect to the J-Link GDB +server, flash the debug firmware and then start execution from the bootloader +(as if the device was just plugged in). ```sh -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64/ +make run-debug ``` +> [!TIP] +> After rebuilding the firmware, exit GDB and rerun `run-debug` to flash and reset the device. + +> [!TIP] +> The initial set of GDB commands that are run are specified in the [gdb init +> script](./scripts/jlink.gdb). You may want to modify it if you are debugging +> something specific. + +> [!TIP] +> In debug builds you can use the following functions to log: +> ```c +> util_log(fmt, args...) +> ``` +> ```rust +> use ::util::log::log!(fmt, args...) +> ``` +> in C you can also format with hex using `util_dbg_hex`: +> ```c +> uint8_t arr[] = {1,2}; +> util_log("%s", util_dbg_hex(arr, sizeof(arr))); +> ``` +> in rust you can format with hex using the built in hex formatter or the hex +> crate: +> ```rust +> let arr = [1, 2]; +> log!("{:02x?}", arr) +> log!("{}", hex::encode(arr)) +> ``` + +### Unit tests + +CMocka [https://cmocka.org/](https://cmocka.org/) is used for mocking in the +unit tests. To compile the tests, the CMocka library needs to be installed on +your system. CMocka is available through most package managers, like *brew* and +*apt*. + +> [!NOTE] +> If you compiled it yourself from souce, the library will, by default, be +> installed into **/usr/local/** directory instead of **/usr/**. +> If the library is not on the library path by default, you might need to export +> the following environment variable: +> ```sh +> export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64/ +> ``` + Then you can run the tests by executing ```sh @@ -220,9 +352,26 @@ make -C build-build coverage-lcovr ### SCCache / CCache -The build systems supports sccache/ccache, you just need to have it available in your path. You can -install it into your dev container with the following commands: +The build systems supports sccache/ccache, you just need to have it available +in your path. You can install it into your dev container with the following +commands: ``` docker exec -u 0 -it bitbox02-firmware-dev bash -c 'apt update && apt install -y libssl-dev && CARGO_HOME=/opt/cargo cargo install --locked sccache' ``` + +## BitBox02 Python Library + +There is a Python api library in `py/bitbox02`. + +### BitBox02 CLI client + +Run `pip install -r py/requirements.txt` to install the deps (virtualenv recommended). + +`make -C py/bitbox02` to generate the protobuf files. + +To kick off some api calls: + +```sh +./py/send_message.py +``` diff --git a/CMakeLists.txt b/CMakeLists.txt index 757c84469..88662b040 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,8 +233,9 @@ endif() # Optimize for size by default set(CMAKE_C_FLAGS_RELEASE "-Os -DNDEBUG") -# Allow gdb extensions if available -set(CMAKE_C_FLAGS_DEBUG "-Og -ggdb") +# (-ggdb) Allow gdb extensions if available +# Optimize debug build for size, optimizing for debug takes to much space. +set(CMAKE_C_FLAGS_DEBUG "-Os -ggdb") set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -ggdb -DNDEBUG") #----------------------------------------------------------------------------- @@ -321,13 +322,15 @@ string(APPEND CMAKE_C_FLAGS " -Wundef -Wmissing-include-dirs") # Disable builtin warning string(APPEND CMAKE_C_FLAGS " -Wno-cast-function-type") -# Hardening -string(APPEND CMAKE_C_FLAGS " -fstack-protector-all") -if(CMAKE_CROSSCOMPILING) - # Path to empty dummy libssp and libssp_shared. '-llibssp -llibssp_shared' is automatically added - # with '-fstack-protector-all', but we don't need them as we have our own custom - # `__stack_chk_fail`. See https://wiki.osdev.org/Stack_Smashing_Protector. - set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/external/lib/ssp") +# Enable stack protection on release builds +if(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") + string(APPEND CMAKE_C_FLAGS " -fstack-protector-all") + if(CMAKE_CROSSCOMPILING) + # Path to empty dummy libssp and libssp_shared. '-llibssp -llibssp_shared' is automatically added + # with '-fstack-protector-all', but we don't need them as we have our own custom + # `__stack_chk_fail`. See https://wiki.osdev.org/Stack_Smashing_Protector. + set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/external/lib/ssp") + endif() endif() # Disallow duplicate definitions, which is the default since GCC diff --git a/Makefile b/Makefile index 071a902fb..90abcd608 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,11 @@ build/Makefile: cd build && cmake -DCMAKE_TOOLCHAIN_FILE=arm.cmake .. $(MAKE) -C py/bitbox02 +build-debug/Makefile: + mkdir -p build-debug + cd build-debug && cmake -DCMAKE_TOOLCHAIN_FILE=arm.cmake -DCMAKE_BUILD_TYPE=DEBUG .. + $(MAKE) -C py/bitbox02 + build-build/Makefile: mkdir -p build-build cd build-build && cmake .. -DCOVERAGE=ON -DSANITIZE_ADDRESS=$(SANITIZE) -DSANITIZE_UNDEFINED=$(SANITIZE) @@ -41,6 +46,9 @@ build-build-rust-unit-tests/Makefile: # Directory for building for "host" machine according to gcc convention build: build/Makefile +# Directory for building debug build for "host" machine according to gcc convention +build-debug: build-debug/Makefile + # Directory for building for "build" machine according to gcc convention build-build: build-build/Makefile @@ -50,10 +58,11 @@ build-build: build-build/Makefile build-build-rust-unit-tests: build-build-rust-unit-tests/Makefile firmware: | build -# Generate python bindings for protobuf for test scripts $(MAKE) -C build firmware.elf firmware-btc: | build $(MAKE) -C build firmware-btc.elf +firmware-debug: | build-debug + $(MAKE) -C build-debug firmware.elf bootloader: | build $(MAKE) -C build bootloader.elf bootloader-development: | build @@ -112,6 +121,14 @@ jlink-flash-firmware-btc: | build JLinkExe -if SWD -device ATSAMD51J20 -speed 4000 -autoconnect 1 -CommanderScript ./build/scripts/firmware-btc.jlink jlink-flash-factory-setup: | build JLinkExe -if SWD -device ATSAMD51J20 -speed 4000 -autoconnect 1 -CommanderScript ./build/scripts/factory-setup.jlink +jlink-flash-firmware-debug: | build + JLinkExe -if SWD -device ATSAMD51J20 -speed 4000 -autoconnect 1 -CommanderScript ./build-debug/scripts/firmware.jlink +jlink-gdb-server: + JLinkGDBServer -nogui -if SWD -device ATSAMD51J20 -speed 4000 +rtt-client: + telnet localhost 19021 +run-debug: + arm-none-eabi-gdb -x scripts/jlink.gdb build-debug/bin/firmware.elf dockerinit: ./scripts/container.sh build --pull --force-rm --no-cache -t shiftcrypto/firmware_v2:$(shell cat .containerversion) . dockerpull: @@ -128,4 +145,4 @@ prepare-tidy: | build build-build make -C build rust-cbindgen make -C build-build rust-cbindgen clean: - rm -rf build build-build build-build-rust-unit-tests + rm -rf build build-build build-debug build-build-rust-unit-tests diff --git a/scripts/jlink.gdb b/scripts/jlink.gdb new file mode 100644 index 000000000..574b64d5c --- /dev/null +++ b/scripts/jlink.gdb @@ -0,0 +1,16 @@ +# Connect to jlink gdb server +target extended-remote :2331 + +# load the firmware into ROM +load + +# Reset the CPU +monitor reset + +#break Reset_Handler +#break HardFault_Handler +#break NMI_Handler +#break MemManage_Handler + +# start running +stepi diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2fee7912b..dcd459c67 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -224,7 +224,11 @@ if(CMAKE_CROSSCOMPILING) set(RUST_TARGET_ARCH thumbv7em-none-eabi) set(RUST_TARGET_ARCH_DIR ${RUST_TARGET_ARCH}) set(RUST_TARGET_ARCH_ARG --target ${RUST_TARGET_ARCH}) - set(RUST_CARGO_FLAGS ${RUST_CARGO_FLAGS} -Zbuild-std=core,alloc -Zbuild-std-features=panic_immediate_abort,optimize_for_size) + if(CMAKE_BUILD_TYPE STREQUAL "DEBUG") + set(RUST_CARGO_FLAGS ${RUST_CARGO_FLAGS} -Zbuild-std=core,alloc -Zbuild-std-features=optimize_for_size) + else() + set(RUST_CARGO_FLAGS ${RUST_CARGO_FLAGS} -Zbuild-std=core,alloc -Zbuild-std-features=panic_immediate_abort,optimize_for_size) + endif() else() set(RUST_TARGET_ARCH_DIR .) endif() @@ -366,7 +370,7 @@ foreach(type ${RUST_LIBS}) FIRMWARE_VERSION_SHORT=${FIRMWARE_VERSION} $<$:RUSTC_WRAPPER=${SCCACHE_PROGRAM}> RUSTC_BOOTSTRAP=1 - ${CARGO} build $<$:-vv> --offline --features target-${type} --target-dir ${RUST_BINARY_DIR}/feature-${type} ${RUST_CARGO_FLAGS} ${RUST_TARGET_ARCH_ARG} + ${CARGO} build $<$:-vv> --offline --features target-${type}$<$:,rtt> --target-dir ${RUST_BINARY_DIR}/feature-${type} ${RUST_CARGO_FLAGS} ${RUST_TARGET_ARCH_ARG} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${lib} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/lib${type}_rust_c.a # DEPFILES are only supported with the Ninja build tool diff --git a/src/platform/platform_init.c b/src/platform/platform_init.c index df6fcaee5..e7be810ee 100644 --- a/src/platform/platform_init.c +++ b/src/platform/platform_init.c @@ -18,11 +18,18 @@ #if !defined(BOOTLOADER) #include "sd_mmc/sd_mmc_start.h" #endif +#include "rust/rust.h" void platform_init(void) { oled_init(); #if !defined(BOOTLOADER) +// The factory setup image already has a c implementation of RTT. +#if FACTORYSETUP != 1 + // these two functions are noops if "rtt" feature isn't enabled in rust + rust_rtt_init(); + util_log("platform_init"); +#endif sd_mmc_start(); #endif } diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 040bdbc1d..797e08ddb 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -30,6 +30,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version 0.2.3", +] + [[package]] name = "base58ck" version = "0.1.0" @@ -182,6 +191,12 @@ dependencies = [ "hex-conservative", ] +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + [[package]] name = "blake2" version = "0.10.6" @@ -253,6 +268,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "critical-section", + "embedded-hal", + "volatile-register", +] + [[package]] name = "cpufeatures" version = "0.2.9" @@ -277,6 +305,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crypto-common" version = "0.1.6" @@ -298,7 +332,7 @@ dependencies = [ "curve25519-dalek-derive", "digest", "fiat-crypto", - "rustc_version", + "rustc_version 0.4.0", "subtle", ] @@ -352,6 +386,16 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + [[package]] name = "erc20_params" version = "0.1.0" @@ -474,6 +518,21 @@ dependencies = [ "bitcoin", ] +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + [[package]] name = "noise-protocol" version = "0.2.0" @@ -589,13 +648,32 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "rtt-target" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10b34c9e6832388e45f3c01f1bb60a016384a0a4ad80cdd7d34913bed25037f0" +dependencies = [ + "critical-section", + "ufmt-write", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.20", ] [[package]] @@ -623,12 +701,27 @@ dependencies = [ "cc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.204" @@ -725,6 +818,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "ufmt-write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" + [[package]] name = "unicode-ident" version = "1.0.5" @@ -745,15 +844,38 @@ dependencies = [ name = "util" version = "0.1.0" dependencies = [ + "cortex-m", "num-bigint", + "rtt-target", ] +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] + [[package]] name = "x25519-dalek" version = "2.0.0" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 13ff0a54b..684ace324 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -40,11 +40,27 @@ zeroize = "1.7.0" # This only affects the .elf output. Debug info is stripped from the final .bin. # Paths to source code can still appear in the final bin, as they are part of the panic!() output. debug = true - +# Optmimize maximally for size, 'z' should produce even less code than 's' opt-level = 'z' +# 1 gives smaller binaries (16 is default in release mode) codegen-units = 1 +# Abort on panics in release builds. panic = 'abort' +# LTO gives smaller binaries due to cross-crate optimizations lto = true +# Mimic the release profile to save as much space as possible [profile.dev] opt-level = 'z' +# Set lto="thin" to get faster builds +lto = true +# Enabling debug assertions will increase binary size +debug-assertions = false +# Enabling overflow checks will increase binary size +overflow-checks = false +# Set to maximally 256 to compile more in parallel +codegen-units = 1 +# Set to 'abort' to save space +panic = 'unwind' +# Set to false to potentially reduce binary size +incremental = true diff --git a/src/rust/bitbox02-rust-c/Cargo.toml b/src/rust/bitbox02-rust-c/Cargo.toml index 0f8f8d71d..1603c1c77 100644 --- a/src/rust/bitbox02-rust-c/Cargo.toml +++ b/src/rust/bitbox02-rust-c/Cargo.toml @@ -96,4 +96,6 @@ app-u2f = [ app-cardano = [ # enable this feature in the deps "bitbox02-rust/app-cardano", -] \ No newline at end of file +] + +rtt = [ "util/rtt" ] diff --git a/src/rust/bitbox02-rust-c/src/lib.rs b/src/rust/bitbox02-rust-c/src/lib.rs index ec83f91e9..6fe78df75 100644 --- a/src/rust/bitbox02-rust-c/src/lib.rs +++ b/src/rust/bitbox02-rust-c/src/lib.rs @@ -36,14 +36,37 @@ mod sha2; mod workflow; // Whenever execution reaches somewhere it isn't supposed to rust code will "panic". Our panic -// handler will print the available information on the screen. If we compile with `panic=abort` -// this code will never get executed. +// handler will print the available information on the screen and over RTT. If we compile with +// `panic=abort` this code will never get executed. #[cfg(not(test))] #[cfg(not(feature = "testing"))] #[cfg_attr(feature = "bootloader", allow(unused_variables))] #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { + ::util::log::log!("{}", info); #[cfg(feature = "firmware")] bitbox02_rust::print_debug!(0, "Error: {}", info); loop {} } + +#[no_mangle] +pub extern "C" fn rust_rtt_init() { + ::util::log::rtt_init(); +} + +/// # Safety +/// +/// The pointer `ptr` must point to a null terminated string +#[no_mangle] +#[cfg_attr(not(feature = "rtt"), allow(unused))] +pub unsafe extern "C" fn rust_log(ptr: *const ::util::c_types::c_char) { + #[cfg(feature = "rtt")] + { + if ptr.is_null() { + panic!("`ptr` must be a valid pointer"); + } + let s = unsafe { core::ffi::CStr::from_ptr(ptr as _) }; + let s = unsafe { core::str::from_utf8_unchecked(s.to_bytes()) }; + ::util::log::rtt_target::rprintln!("{}", s); + } +} diff --git a/src/rust/util/Cargo.toml b/src/rust/util/Cargo.toml index c1c66bfd6..9b92659eb 100644 --- a/src/rust/util/Cargo.toml +++ b/src/rust/util/Cargo.toml @@ -22,3 +22,8 @@ license = "Apache-2.0" [dependencies] num-bigint = { workspace = true, default-features = false } +rtt-target = { version = "0.5.0", optional = true } +cortex-m = { version = "0.7.7", features = ["critical-section-single-core"], optional = true } + +[features] +rtt = ["dep:rtt-target", "dep:cortex-m"] diff --git a/src/rust/util/src/lib.rs b/src/rust/util/src/lib.rs index 304fa535c..ea6654fb4 100644 --- a/src/rust/util/src/lib.rs +++ b/src/rust/util/src/lib.rs @@ -17,12 +17,17 @@ pub mod ascii; pub mod bip32; pub mod c_types; pub mod decimal; +pub mod log; pub mod name; // for `format!` #[macro_use] extern crate alloc; +// include critical section implementation, needed by rtt-target +#[cfg(feature = "rtt")] +extern crate cortex_m; + /// Guaranteed to wipe the provided buffer pub fn zero(dst: &mut [u8]) { for p in dst { diff --git a/src/rust/util/src/log.rs b/src/rust/util/src/log.rs new file mode 100644 index 000000000..58092bf62 --- /dev/null +++ b/src/rust/util/src/log.rs @@ -0,0 +1,18 @@ +// Re-export rtt_target so that it is available to the macro user +#[cfg(feature = "rtt")] +pub use ::rtt_target; + +/// Macro to log over RTT if `rtt` feature is set, otherwise noop +#[macro_export] +macro_rules! log { + ($($arg:tt)*) => { #[cfg(feature="rtt")] {$crate::log::rtt_target::rprintln!($($arg)*) }}; +} + +// Make log macro usable in crate +pub use log; + +pub fn rtt_init() { + #[cfg(feature = "rtt")] + rtt_target::rtt_init_print!(); + log!("RTT Initialized"); +} diff --git a/src/rust/vendor/bare-metal/.cargo-checksum.json b/src/rust/vendor/bare-metal/.cargo-checksum.json new file mode 100644 index 000000000..07d855e26 --- /dev/null +++ b/src/rust/vendor/bare-metal/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"cbe525fd84e5a7141bcee4fe5ae0c7ff9e1e50da7996277f902859a90600b8e4","Cargo.toml":"fb997fae9de7404a3b148f83ac3f03e84a19d16870843167dadd80e988ac098f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"035e70219855119df4273b3c5b97543ae82e0dd60c520416e759107c602f651b","README.md":"afa5b1c70325ec18dbfcea11faa65a3d83368c2c907c158f7acb39736b3e0d94","bors.toml":"b96eaac6b3dc8487a2bcc6cb415e745a28d9a61937090df48186c62d2b614aeb","build.rs":"9485deb6c0ab46ed05b1fabfb62518fa6f9fbdcf7a207d4cb6844dc6df70f4d7","ci/install.sh":"e295d97db9e12ac6ee3e523e4597ad58fedcca2b8aa3a21302951ad2327b88a9","ci/script.sh":"e2c28462deea39c9ea792fa7069b9afdb6f561901aa1878ea27046c8ad058e43","src/lib.rs":"9197c65b0daec25ebb5e8c5587f82affaa35757b785a539ebb35ce91dae98b7d"},"package":"5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"} \ No newline at end of file diff --git a/src/rust/vendor/bare-metal/CHANGELOG.md b/src/rust/vendor/bare-metal/CHANGELOG.md new file mode 100644 index 000000000..a06a869fc --- /dev/null +++ b/src/rust/vendor/bare-metal/CHANGELOG.md @@ -0,0 +1,77 @@ +# Change Log + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.2.5] - 2019-08-29 + +### Changed + +- The `const-fn` feature is now stable + +## [v0.2.4] - 2018-10-30 + +### Added + +- Note in the documentation that `Mutex` is not memory safe in multi-core systems. + +### Changed + +- The `const-fn` feature can now be used on 1.31-beta and will also work on stable 1.31. + +## [v0.2.3] - 2018-08-17 + +### Fixed + +- A compilation error when using a recent nightly while the "const-fn" feature was enabled. + +## [v0.2.2] - 2018-08-17 - YANKED + +### Fixed + +- A compilation error when using a recent nightly while the "const-fn" feature was enabled. + +## [v0.2.1] - 2018-08-03 + +### Fixed + +- Soundness issue where it was possible to borrow the contents of a Mutex for longer than the + lifetime of the Mutex. + +## [v0.2.0] - 2018-05-10 - YANKED + +YANKED due to a soundness issue: see v0.2.1 for details + +### Changed + +- [breaking-change] `const-fn` is no longer a default feature (i.e. a feature that's enabled by + default). The consequence is that this crate now compiles on 1.27 (beta) by default, and opting + into `const-fn` requires nightly. + +## [v0.1.2] - 2018-04-24 + +### Added + +- An opt-out "const-fn" Cargo feature. When this feature is disabled this crate compiles on stable. + +## [v0.1.1] - 2017-09-19 + +### Fixed + +- Added feature gate to make this work on recent nightlies + +## v0.1.0 - 2017-07-06 + +- Initial release + +[Unreleased]: https://github.com/japaric/bare-metal/compare/v0.2.5...HEAD +[v0.2.5]: https://github.com/japaric/bare-metal/compare/v0.2.4...v0.2.5 +[v0.2.4]: https://github.com/japaric/bare-metal/compare/v0.2.3...v0.2.4 +[v0.2.3]: https://github.com/japaric/bare-metal/compare/v0.2.2...v0.2.3 +[v0.2.2]: https://github.com/japaric/bare-metal/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/japaric/bare-metal/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/japaric/bare-metal/compare/v0.1.2...v0.2.0 +[v0.1.2]: https://github.com/japaric/bare-metal/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/japaric/bare-metal/compare/v0.1.0...v0.1.1 diff --git a/src/rust/vendor/bare-metal/Cargo.toml b/src/rust/vendor/bare-metal/Cargo.toml new file mode 100644 index 000000000..0c57fd970 --- /dev/null +++ b/src/rust/vendor/bare-metal/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bare-metal" +version = "0.2.5" +authors = ["Jorge Aparicio "] +description = "Abstractions common to bare metal systems" +documentation = "https://docs.rs/bare-metal" +keywords = ["bare-metal", "register", "peripheral", "interrupt"] +categories = ["embedded", "hardware-support", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/japaric/bare-metal" +[build-dependencies.rustc_version] +version = "0.2.3" + +[features] +const-fn = [] diff --git a/src/rust/vendor/bare-metal/LICENSE-APACHE b/src/rust/vendor/bare-metal/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/bare-metal/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/bare-metal/LICENSE-MIT b/src/rust/vendor/bare-metal/LICENSE-MIT new file mode 100644 index 000000000..a128ba402 --- /dev/null +++ b/src/rust/vendor/bare-metal/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/bare-metal/README.md b/src/rust/vendor/bare-metal/README.md new file mode 100644 index 000000000..b540f8859 --- /dev/null +++ b/src/rust/vendor/bare-metal/README.md @@ -0,0 +1,21 @@ +# `bare-metal` + +> Abstractions common to bare metal systems + +## [Change log](CHANGELOG.md) + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/src/rust/vendor/bare-metal/bors.toml b/src/rust/vendor/bare-metal/bors.toml new file mode 100644 index 000000000..5ccee21e0 --- /dev/null +++ b/src/rust/vendor/bare-metal/bors.toml @@ -0,0 +1,3 @@ +status = [ + "continuous-integration/travis-ci/push", +] \ No newline at end of file diff --git a/src/rust/vendor/bare-metal/build.rs b/src/rust/vendor/bare-metal/build.rs new file mode 100644 index 000000000..f197f20f5 --- /dev/null +++ b/src/rust/vendor/bare-metal/build.rs @@ -0,0 +1,9 @@ +extern crate rustc_version; + +fn main() { + let vers = rustc_version::version().unwrap(); + + if vers.major == 1 && vers.minor < 31 { + println!("cargo:rustc-cfg=unstable_const_fn") + } +} diff --git a/src/rust/vendor/bare-metal/ci/install.sh b/src/rust/vendor/bare-metal/ci/install.sh new file mode 100644 index 000000000..3c4192119 --- /dev/null +++ b/src/rust/vendor/bare-metal/ci/install.sh @@ -0,0 +1,9 @@ +set -euxo pipefail + +main() { + if [ $TARGET != x86_64-unknown-linux-gnu ]; then + rustup target add $TARGET + fi +} + +main diff --git a/src/rust/vendor/bare-metal/ci/script.sh b/src/rust/vendor/bare-metal/ci/script.sh new file mode 100644 index 000000000..b0aec2299 --- /dev/null +++ b/src/rust/vendor/bare-metal/ci/script.sh @@ -0,0 +1,11 @@ +set -euxo pipefail + +main() { + cargo check --target $TARGET + + if [ $TARGET = x86_64-unknown-linux-gnu ]; then + cargo test + fi +} + +main diff --git a/src/rust/vendor/bare-metal/src/lib.rs b/src/rust/vendor/bare-metal/src/lib.rs new file mode 100644 index 000000000..47a6b8edc --- /dev/null +++ b/src/rust/vendor/bare-metal/src/lib.rs @@ -0,0 +1,101 @@ +//! Abstractions common to bare metal systems + +#![deny(missing_docs)] +#![deny(warnings)] +#![no_std] + +use core::cell::UnsafeCell; + +/// A peripheral +#[derive(Debug)] +pub struct Peripheral +where + T: 'static, +{ + address: *mut T, +} + +impl Peripheral { + /// Creates a new peripheral + /// + /// `address` is the base address of the register block + pub const unsafe fn new(address: usize) -> Self { + Peripheral { + address: address as *mut T, + } + } + + /// Borrows the peripheral for the duration of a critical section + pub fn borrow<'cs>(&self, _ctxt: &'cs CriticalSection) -> &'cs T { + unsafe { &*self.get() } + } + + /// Returns a pointer to the register block + pub fn get(&self) -> *mut T { + self.address as *mut T + } +} + +/// Critical section token +/// +/// Indicates that you are executing code within a critical section +pub struct CriticalSection { + _0: (), +} + +impl CriticalSection { + /// Creates a critical section token + /// + /// This method is meant to be used to create safe abstractions rather than + /// meant to be directly used in applications. + pub unsafe fn new() -> Self { + CriticalSection { _0: () } + } +} + +/// A "mutex" based on critical sections +/// +/// # Safety +/// +/// **This Mutex is only safe on single-core systems.** +/// +/// On multi-core systems, a `CriticalSection` **is not sufficient** to ensure exclusive access. +pub struct Mutex { + inner: UnsafeCell, +} + +impl Mutex { + /// Creates a new mutex + pub const fn new(value: T) -> Self { + Mutex { + inner: UnsafeCell::new(value), + } + } +} + +impl Mutex { + /// Borrows the data for the duration of the critical section + pub fn borrow<'cs>(&'cs self, _cs: &'cs CriticalSection) -> &'cs T { + unsafe { &*self.inner.get() } + } +} + +/// ``` compile_fail +/// fn bad(cs: &bare_metal::CriticalSection) -> &u32 { +/// let x = bare_metal::Mutex::new(42u32); +/// x.borrow(cs) +/// } +/// ``` +#[allow(dead_code)] +const GH_6: () = (); + +/// Interrupt number +pub unsafe trait Nr { + /// Returns the number associated with an interrupt + fn nr(&self) -> u8; +} + +// NOTE A `Mutex` can be used as a channel so the protected data must be `Send` +// to prevent sending non-Sendable stuff (e.g. access tokens) across different +// execution contexts (e.g. interrupts) +unsafe impl Sync for Mutex where T: Send {} diff --git a/src/rust/vendor/bitfield/.cargo-checksum.json b/src/rust/vendor/bitfield/.cargo-checksum.json new file mode 100644 index 000000000..d0313d909 --- /dev/null +++ b/src/rust/vendor/bitfield/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"c4945aec76bc2731a0497b605f863a7a11390cadd1d0ff59ae2b2fa2d03f0dda","Cargo.toml":"f36c4d7ba9d81f7105f178eaee447b032ba2f8710e05c6e43fca4fd85e50b549","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"af6b8d2c7ab89b819e3c2db77b572f145d14c8578dbd25015d739b30d4cc92f7","README.md":"0508f6529346eb36ac57497cc72c68e8e64e4f2aac7df2e9395582edfeead850","examples/bits_position.rs":"a00a3c79cb1d87e34e94372bb673a8a468e397ffca437acfbeda1228b2aa99e1","examples/ipv4.rs":"153d81430b512d2277c134c3b29e23924a23fb416c83a3eb010267e98ff0c30c","multitest.toml":"0ad084611444cc582d5421dfac4ef9e9893fd76a4a87d7132e80668f8531eafa","src/lib.rs":"4178acd8676440ac01dc406d23511ff77657d34231343528294d5c12dfa76290","tests/lib.rs":"8a1723a1e34287109cb807d3af318ab22869952d16cde633d6462faaa9e00886"},"package":"46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"} \ No newline at end of file diff --git a/src/rust/vendor/bitfield/CHANGELOG.md b/src/rust/vendor/bitfield/CHANGELOG.md new file mode 100644 index 000000000..837f22459 --- /dev/null +++ b/src/rust/vendor/bitfield/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.13.2] - 2019-05-28 + +### Added +- `from into` can be used in place of `from` to change the input type of the setter. Thanks to @roblabla + +[Unreleased]: https://github.com/dzamlo/rust-bitfield/compare/v0.13.1...HEAD +[0.13.2]: https://github.com/dzamlo/rust-bitfield/compare/v0.13.1...v0.13.2 + diff --git a/src/rust/vendor/bitfield/Cargo.toml b/src/rust/vendor/bitfield/Cargo.toml new file mode 100644 index 000000000..e2f4752d1 --- /dev/null +++ b/src/rust/vendor/bitfield/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bitfield" +version = "0.13.2" +authors = ["Loïc Damien "] +description = "This crate provides macros to generate bitfield-like struct." +documentation = "https://docs.rs/bitfield" +license = "MIT OR Apache-2.0" +repository = "https://github.com/dzamlo/rust-bitfield" + +[dependencies] diff --git a/src/rust/vendor/bitfield/LICENSE-APACHE b/src/rust/vendor/bitfield/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/src/rust/vendor/bitfield/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/src/rust/vendor/bitfield/LICENSE-MIT b/src/rust/vendor/bitfield/LICENSE-MIT new file mode 100644 index 000000000..b964553c0 --- /dev/null +++ b/src/rust/vendor/bitfield/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2017 Loïc Damien + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/rust/vendor/bitfield/README.md b/src/rust/vendor/bitfield/README.md new file mode 100644 index 000000000..ac327053a --- /dev/null +++ b/src/rust/vendor/bitfield/README.md @@ -0,0 +1,57 @@ +rust-bitfield +============= + +This crate provides macros to generate bitfield-like struct. + +This a complete rewrite of the `bitfield` crate. +You can find the previous version in the [rust-bitfield-legacy](https://github.com/dzamlo/rust-bitfield-legacy) repository. This version works on the stable version of rustc and use a different syntax with different possibility. + + +## Example + +An IPv4 header could be described like that: + +```rust +bitfield!{ + struct IpV4Header(MSB0 [u8]); + u32; + get_version, _: 3, 0; + get_ihl, _: 7, 4; + get_dscp, _: 13, 8; + get_ecn, _: 15, 14; + get_total_length, _: 31, 16; + get_identification, _: 47, 31; + get_df, _: 49; + get_mf, _: 50; + get_fragment_offset, _: 63, 51; + get_time_to_live, _: 71, 64; + get_protocol, _: 79, 72; + get_header_checksum, _: 95, 79; + get_source_address, _: 127, 96; + get_destination_address, _: 159, 128; +} +``` + +In this example, all the fields are read-only, the _ as setter name signals to skip the setter method. +The range at the end (e.g. 3, 0) defines the bit range where the information is encoded. + +## Documentation + +The documentation of the released version is available on [doc.rs](https://docs.rs/bitfield). + + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/src/rust/vendor/bitfield/examples/bits_position.rs b/src/rust/vendor/bitfield/examples/bits_position.rs new file mode 100644 index 000000000..0bcf360e8 --- /dev/null +++ b/src/rust/vendor/bitfield/examples/bits_position.rs @@ -0,0 +1,75 @@ +#[macro_use] +extern crate bitfield; + +use bitfield::Bit; +use bitfield::BitRange; + +bitfield! { + struct BitsLocations([u8]); +} + +bitfield! { + struct BitsLocationsMsb0(MSB0 [u8]); +} + +fn println_slice_bits(slice: &[u8]) { + if slice.is_empty() { + println!("[]"); + } else { + print!("[{:08b}", slice[0]); + + for byte in &slice[1..] { + print!(", {:08b}", byte); + } + + println!("]"); + } +} + +fn main() { + let mut bits_locations = BitsLocations([0; 3]); + let mut bits_locations_msb0 = BitsLocationsMsb0([0; 3]); + + println!("Default version:"); + for i in 0..(3 * 8) { + bits_locations.set_bit(i, true); + print!("{:2}: ", i); + println_slice_bits(&bits_locations.0); + bits_locations.set_bit(i, false); + } + + for i in 0..(3 * 8 - 3) { + let msb = i + 3; + let lsb = i; + for value in &[0b1111u8, 0b0001, 0b1000] { + bits_locations.set_bit_range(msb, lsb, *value); + print!("{:2} - {:2} ({:04b}): ", msb, lsb, value); + println_slice_bits(&bits_locations.0); + } + println!(); + bits_locations.set_bit_range(msb, lsb, 0u8); + } + + println!("MSB0 version:"); + + for i in 0..(3 * 8) { + bits_locations_msb0.set_bit(i, true); + print!("{:2}: ", i); + println_slice_bits(&bits_locations_msb0.0); + + bits_locations_msb0.set_bit(i, false); + } + + for i in 0..(3 * 8 - 3) { + let msb = i + 3; + let lsb = i; + for value in &[0b1111u8, 0b0001, 0b1000] { + bits_locations_msb0.set_bit_range(msb, lsb, *value); + print!("{:2} - {:2} ({:04b}): ", msb, lsb, value); + println_slice_bits(&bits_locations_msb0.0); + } + println!(); + + bits_locations_msb0.set_bit_range(msb, lsb, 0u8); + } +} diff --git a/src/rust/vendor/bitfield/examples/ipv4.rs b/src/rust/vendor/bitfield/examples/ipv4.rs new file mode 100644 index 000000000..93cedcdbf --- /dev/null +++ b/src/rust/vendor/bitfield/examples/ipv4.rs @@ -0,0 +1,60 @@ +#![allow(dead_code)] + +#[macro_use] +extern crate bitfield; + +use std::net::Ipv4Addr; + +bitfield! { + struct IpV4Header(MSB0 [u8]); + impl Debug; + u32; + get_version, _: 3, 0; + get_ihl, _: 7, 4; + get_dscp, _: 13, 8; + get_ecn, _: 15, 14; + get_total_length, _: 31, 16; + get_identification, _: 47, 31; + get_df, _: 49; + get_mf, _: 50; + get_fragment_offset, _: 63, 51; + get_time_to_live, _: 71, 64; + get_protocol, _: 79, 72; + get_header_checksum, _: 95, 79; + u8, get_source_address, _: 103, 96, 4; + u32, into Ipv4Addr, get_destination_address, _: 159, 128; +} + +impl + AsMut<[u8]>> IpV4Header { + fn get_source_as_ip_addr(&self) -> Ipv4Addr { + let mut src = [0; 4]; + for (i, src) in src.iter_mut().enumerate() { + *src = self.get_source_address(i); + } + src.into() + } +} + +fn main() { + let data = [ + 0x45, 0x00, 0x00, 0x40, 0x69, 0x27, 0x40, 0x00, 0x40, 0x11, 0x4d, 0x0d, 0xc0, 0xa8, 0x01, + 0x2a, 0xc0, 0xa8, 0x01, 0xfe, + ]; + + let header = IpV4Header(data); + + assert_eq!(header.get_version(), 4); + assert_eq!(header.get_total_length(), 64); + assert_eq!(header.get_identification(), 0x6927); + assert!(header.get_df()); + assert!(!header.get_mf()); + assert_eq!(header.get_fragment_offset(), 0); + assert_eq!(header.get_protocol(), 0x11); + println!( + "from {} to {}", + header.get_source_as_ip_addr(), + header.get_destination_address() + ); + + println!("{:#?}", header); +} diff --git a/src/rust/vendor/bitfield/multitest.toml b/src/rust/vendor/bitfield/multitest.toml new file mode 100644 index 000000000..bb62f253a --- /dev/null +++ b/src/rust/vendor/bitfield/multitest.toml @@ -0,0 +1,22 @@ +[[tests]] +name = "cargo-test-{{toolchain}}" +command = ["cargo", "+{{toolchain}}", "test", "--all", "--frozen"] + +[[tests.env]] +name = "CARGO_TARGET_DIR" +value = "target/{{name}}" + +[tests.variables] +toolchain = ["stable", "beta", "nightly", "1.26.0"] + +[[tests]] +name = "cargo-clippy" +command = ["cargo", "+nightly", "clippy", "--all", "--frozen", "--all-targets", "--", "-D", "warnings"] + +[[tests.env]] +name = "CARGO_TARGET_DIR" +value = "target/cargo-test-nightly" + +[[tests]] +name = "cargo-fmt" +command = ["cargo", "fmt", "--all", "--", "--check"] diff --git a/src/rust/vendor/bitfield/src/lib.rs b/src/rust/vendor/bitfield/src/lib.rs new file mode 100644 index 000000000..749df7762 --- /dev/null +++ b/src/rust/vendor/bitfield/src/lib.rs @@ -0,0 +1,668 @@ +#![no_std] +#![deny( + missing_docs, + unused_extern_crates, + unused_import_braces, + unused_qualifications +)] + +//! This crate provides macros to generate bitfield-like struct. +//! +//! See the documentation of the macros for how to use them. +//! +//! Examples and tests are also a great way to understand how to use these macros. + +/// Declares the fields of struct. +/// +/// This macro will generate the methods to access the fields of a bitfield. It must be called +/// from an `impl` block for a type that implements the `BitRange` and/or the `Bit` traits +/// (which traits are required depending on what type of fields are used). +/// +/// The syntax of this macro is composed of declarations ended by semicolons. There are two types +/// of declarations: default type, and fields. +/// +/// A default type is just a type followed by a semicolon. This will affect all the following field +/// declarations. +/// +/// A field declaration is composed of the following: +/// +/// * Optional attributes (`#[...]`), documentation comments (`///`) are attributes; +/// * An optional pub keyword to make the methods public +/// * An optional type followed by a comma +/// * Optionally, the word `into` followed by a type, followed by a comma +/// * The getter and setter idents, separated by a comma +/// * A colon +/// * One to three expressions of type `usize` +/// +/// The attributes and pub will be applied to the two methods generated. +/// +/// If the `into` part is used, the getter will convert the field after reading it. +/// +/// The getter and setter idents can be `_` to not generate one of the two. For example, if the +/// setter is `_`, the field will be read-only. +/// +/// The expressions at the end are the bit positions. Their meaning depends on the number of +/// expressions: +/// +/// * One expression: the field is a single bit. The type is ignored and `bool` is used. The trait +/// `Bit` is used. +/// * Two expressions: `msb, lsb`, the field is composed of the bits from `msb` to `lsb`, included. +/// * Three expressions: `msb, lsb, count`, the field is an array. The first element is composed of +/// the bits from `msb` to `lsb`. The following elements are consecutive bits range of the same +/// size. +/// +/// # Example +/// +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// # fn main() {} +/// # struct FooBar(u64); +/// # bitfield_bitrange!{struct FooBar(u64)} +/// # impl From for FooBar{ fn from(_: u32) -> FooBar {unimplemented!()}} +/// # impl From for u32{ fn from(_: FooBar) -> u32 {unimplemented!()}} +/// # impl FooBar { +/// bitfield_fields!{ +/// // The default type will be `u64 +/// u64; +/// // filed1 is read-write, public, the methods are inline +/// #[inline] +/// pub field1, set_field1: 10, 0; +/// // `field2` is read-only, private, and of type bool. +/// field2, _ : 0; +/// // `field3` will be read as an `u32` and then converted to `FooBar`. +/// // The setter is not affected, it still need an `u32` value. +/// u32, into FooBar, field3, set_field3: 10, 0; +/// // `field4` will be read as an `u32` and then converted to `FooBar`. +/// // The setter will take a `FooBar`, and converted back to an `u32`. +/// u32, from into FooBar, field4, set_field4: 10, 0; +/// } +/// # } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitfield_fields { + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, + $lsb:expr, $count:expr) => { + $(#[$attribute])* + #[allow(unknown_lints)] + #[allow(eq_op)] + $($vis)* fn $setter(&mut self, index: usize, value: $from) { + use $crate::BitRange; + __bitfield_debug_assert!(index < $count); + let width = $msb - $lsb + 1; + let lsb = $lsb + index*width; + let msb = lsb + width - 1; + self.set_bit_range(msb, lsb, $crate::Into::<$t>::into(value)); + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, + $lsb:expr) => { + $(#[$attribute])* + $($vis)* fn $setter(&mut self, value: $from) { + use $crate::BitRange; + self.set_bit_range($msb, $lsb, $crate::Into::<$t>::into(value)); + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $bit:expr) => { + $(#[$attribute])* + $($vis)* fn $setter(&mut self, value: bool) { + use $crate::Bit; + self.set_bit($bit, value); + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, + $lsb:expr, $count:expr) => { + $(#[$attribute])* + #[allow(unknown_lints)] + #[allow(eq_op)] + $($vis)* fn $getter(&self, index: usize) -> $into { + use $crate::BitRange; + __bitfield_debug_assert!(index < $count); + let width = $msb - $lsb + 1; + let lsb = $lsb + index*width; + let msb = lsb + width - 1; + let raw_value: $t = self.bit_range(msb, lsb); + $crate::Into::into(raw_value) + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, + $lsb:expr) => { + $(#[$attribute])* + $($vis)* fn $getter(&self) -> $into { + use $crate::BitRange; + let raw_value: $t = self.bit_range($msb, $lsb); + $crate::Into::into(raw_value) + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $bit:expr) => { + $(#[$attribute])* + $($vis)* fn $getter(&self) -> bool { + use $crate::Bit; + self.bit($bit) + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, $setter:ident: + $($exprs:expr),*) => { + bitfield_fields!(@field $(#[$attribute])* ($($vis)*) $t, $from, $into, $getter, _: $($exprs),*); + bitfield_fields!(@field $(#[$attribute])* ($($vis)*) $t, $from, $into, _, $setter: $($exprs),*); + }; + + ($t:ty;) => {}; + ($default_ty:ty; pub $($rest:tt)*) => { + bitfield_fields!{$default_ty; () pub $($rest)*} + }; + ($default_ty:ty; #[$attribute:meta] $($rest:tt)*) => { + bitfield_fields!{$default_ty; (#[$attribute]) $($rest)*} + }; + ($default_ty:ty; ($(#[$attributes:meta])*) #[$attribute:meta] $($rest:tt)*) => { + bitfield_fields!{$default_ty; ($(#[$attributes])* #[$attribute]) $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $t, $into, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $t, $t, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $t, $t, $t, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $into, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $default_ty, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $default_ty, $default_ty, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + + ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $t, $into, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + + ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $t, $t, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + + ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $t, $t, $t, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $default_ty, $into, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $default_ty, $default_ty, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $default_ty, $default_ty, $default_ty, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($previous_default_ty:ty; $default_ty:ty; $($rest:tt)*) => { + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; $($rest:tt)*) => { + bitfield_fields!{$default_ty; () $($rest)*} + }; + ($($rest:tt)*) => { + bitfield_fields!{SET_A_DEFAULT_TYPE_OR_SPECIFY_THE_TYPE_FOR_EACH_FIELDS; $($rest)*} + } +} + +/// Generates a `fmt::Debug` implementation. +/// +/// This macros must be called from a `impl Debug for ...` block. It will generate the `fmt` method. +/// +/// In most of the case, you will not directly call this macros, but use `bitfield`. +/// +/// The syntax is `struct TheNameOfTheStruct` followed by the syntax of `bitfield_fields`. +/// +/// The write-only fields are ignored. +/// +/// # Example +/// +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// struct FooBar(u32); +/// bitfield_bitrange!{struct FooBar(u32)} +/// impl FooBar{ +/// bitfield_fields!{ +/// u32; +/// field1, _: 7, 0; +/// field2, _: 31, 24; +/// } +/// } +/// +/// impl std::fmt::Debug for FooBar { +/// bitfield_debug!{ +/// struct FooBar; +/// field1, _: 7, 0; +/// field2, _: 31, 24; +/// } +/// } +/// +/// fn main() { +/// let foobar = FooBar(0x11223344); +/// println!("{:?}", foobar); + +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitfield_debug { + (struct $name:ident; $($rest:tt)*) => { + fn fmt(&self, f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result { + let mut debug_struct = f.debug_struct(__bitfield_stringify!($name)); + debug_struct.field(".0", &self.0); + bitfield_debug!{debug_struct, self, $($rest)*} + debug_struct.finish() + } + }; + ($debug_struct:ident, $self:ident, #[$attribute:meta] $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, pub $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, _, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $type:ty; $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $getter:ident, $setter:tt: $msb:expr, $lsb:expr, $count:expr; + $($rest:tt)*) => { + let mut array = [$self.$getter(0); $count]; + for (i, e) in (&mut array).into_iter().enumerate() { + *e = $self.$getter(i); + } + $debug_struct.field(__bitfield_stringify!($getter), &array); + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $getter:ident, $setter:tt: $($exprs:expr),*; $($rest:tt)*) + => { + $debug_struct.field(__bitfield_stringify!($getter), &$self.$getter()); + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, from into $into:ty, $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, into $into:ty, $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $type:ty, $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, ) => {}; +} + +/// Implements `BitRange` for a tuple struct (or "newtype"). +/// +/// This macro will generate an implementation of the `BitRange` trait for an existing single +/// element tuple struct. +/// +/// The syntax is more or less the same as declaring a "newtype", **without** the attributes, +/// documentation comments and pub keyword. +/// +/// The difference with a normal "newtype" is the type in parentheses. If the type is `[t]` (where +/// `t` is any of the unsigned integer type), the "newtype" will be generic and implement +/// `BitRange` for `T: AsMut<[t]> + AsRef<[t]>` (for example a slice, an array or a `Vec`). You can +/// also use `MSB0 [t]`. The difference will be the positions of the bit. You can use the +/// `bits_positions` example to see where each bits is. If the type is neither of this two, the +/// "newtype" will wrap a value of the specified type and implements `BitRange` the same ways as +/// the wrapped type. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// # fn main() {} +/// struct BitField1(u32); +/// bitfield_bitrange!{struct BitField1(u32)} +/// +/// struct BitField2(T); +/// bitfield_bitrange!{struct BitField2([u8])} +/// +/// struct BitField3(T); +/// bitfield_bitrange!{struct BitField3(MSB0 [u8])} +/// ``` +/// +#[macro_export(local_inner_macros)] +macro_rules! bitfield_bitrange { + (@impl_bitrange_slice $name:ident, $slice_ty:ty, $bitrange_ty:ty) => { + impl + AsRef<[$slice_ty]>> $crate::BitRange<$bitrange_ty> + for $name { + fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { + let bit_len = $crate::size_of::<$slice_ty>()*8; + let value_bit_len = $crate::size_of::<$bitrange_ty>()*8; + let mut value = 0; + for i in (lsb..=msb).rev() { + value <<= 1; + value |= ((self.0.as_ref()[i/bit_len] >> (i%bit_len)) & 1) as $bitrange_ty; + } + value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) + } + + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { + let bit_len = $crate::size_of::<$slice_ty>()*8; + let mut value = value; + for i in lsb..=msb { + self.0.as_mut()[i/bit_len] &= !(1 << (i%bit_len)); + self.0.as_mut()[i/bit_len] |= (value & 1) as $slice_ty << (i%bit_len); + value >>= 1; + } + } + } + }; + (@impl_bitrange_slice_msb0 $name:ident, $slice_ty:ty, $bitrange_ty:ty) => { + impl + AsRef<[$slice_ty]>> $crate::BitRange<$bitrange_ty> + for $name { + fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { + let bit_len = $crate::size_of::<$slice_ty>()*8; + let value_bit_len = $crate::size_of::<$bitrange_ty>()*8; + let mut value = 0; + for i in lsb..=msb { + value <<= 1; + value |= ((self.0.as_ref()[i/bit_len] >> (bit_len - i%bit_len - 1)) & 1) + as $bitrange_ty; + } + value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) + } + + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { + let bit_len = $crate::size_of::<$slice_ty>()*8; + let mut value = value; + for i in (lsb..=msb).rev() { + self.0.as_mut()[i/bit_len] &= !(1 << (bit_len - i%bit_len - 1)); + self.0.as_mut()[i/bit_len] |= (value & 1) as $slice_ty + << (bit_len - i%bit_len - 1); + value >>= 1; + } + } + } + }; + (struct $name:ident([$t:ty])) => { + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u8); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u16); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u32); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u64); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u128); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i8); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i16); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i32); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i64); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i128); + }; + (struct $name:ident(MSB0 [$t:ty])) => { + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u8); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u16); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u32); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u64); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u128); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i8); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i16); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i32); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i64); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i128); + }; + (struct $name:ident($t:ty)) => { + impl $crate::BitRange for $name where $t: $crate::BitRange { + fn bit_range(&self, msb: usize, lsb: usize) -> T { + self.0.bit_range(msb, lsb) + } + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T) { + self.0.set_bit_range(msb, lsb, value); + } + } + }; +} + +/// Combines `bitfield_bitrange` and `bitfield_fields`. +/// +/// The syntax of this macro is the syntax of a tuple struct, including attributes and +/// documentation comments, followed by a semicolon, some optional elements, and finally the fields +/// as described in the `bitfield_fields` documentation. +/// +/// The first optional element is `no default BitRange;`. With that, no implementation of +/// `BitRange` will be generated. +/// +/// The second optional element is `impl Debug;`. This will generate an implementation of +/// `fmt::Debug` with the `bitfield_debug` macro. +/// +/// The difference with calling those macros separately is that `bitfield_fields` is called +/// from an appropriate `impl` block. If you use the non-slice form of `bitfield_bitrange`, the +/// default type for `bitfield_fields` will be set to the wrapped fields. +/// +/// See the documentation of these macros for more information on their respective syntax. +/// +/// # Example +/// +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// # fn main() {} +/// bitfield!{ +/// pub struct BitField1(u16); +/// impl Debug; +/// // The fields default to u16 +/// field1, set_field1: 10, 0; +/// pub field2, _ : 12, 3; +/// } +/// ``` +/// +/// or with a custom `BitRange` implementation : +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// # use bitfield::BitRange; +/// # fn main() {} +/// bitfield!{ +/// pub struct BitField1(u16); +/// no default BitRange; +/// impl Debug; +/// u8; +/// field1, set_field1: 10, 0; +/// pub field2, _ : 12, 3; +/// } +/// impl BitRange for BitField1 { +/// fn bit_range(&self, msb: usize, lsb: usize) -> u8 { +/// let width = msb - lsb + 1; +/// let mask = (1 << width) - 1; +/// ((self.0 >> lsb) & mask) as u8 +/// } +/// fn set_bit_range(&mut self, msb: usize, lsb: usize, value: u8) { +/// self.0 = (value as u16) << lsb; +/// } +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitfield { + ($(#[$attribute:meta])* pub struct $($rest:tt)*) => { + bitfield!($(#[$attribute])* (pub) struct $($rest)*); + }; + ($(#[$attribute:meta])* struct $($rest:tt)*) => { + bitfield!($(#[$attribute])* () struct $($rest)*); + }; + // Force `impl Debug` to always be after `no default BitRange` it the two are present. + // This simplify the rest of the macro. + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($($type:tt)*); impl Debug; no default BitRange; $($rest:tt)*) => { + bitfield!{$(#[$attribute])* ($($vis)*) struct $name($($type)*); no default BitRange; impl Debug; $($rest)*} + }; + + // If we have `impl Debug` without `no default BitRange`, we will still match, because when + // we call `bitfield_bitrange`, we add `no default BitRange`. + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); no default BitRange; impl Debug; $($rest:tt)*) => { + impl + AsRef<[$t]> + $crate::fmt::Debug> $crate::fmt::Debug for $name { + bitfield_debug!{struct $name; $($rest)*} + } + + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); no default BitRange; $($rest:tt)*) => { + $(#[$attribute])* + $($vis)* struct $name(pub T); + + impl + AsRef<[$t]>> $name { + bitfield_fields!{$($rest)*} + } + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); $($rest:tt)*) => { + bitfield_bitrange!(struct $name([$t])); + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + + // The only difference between the MSB0 version anf the non-MSB0 version, is the BitRange + // implementation. We delegate everything else to the non-MSB0 version of the macro. + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident(MSB0 [$t:ty]); no default BitRange; $($rest:tt)*) => { + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident(MSB0 [$t:ty]); $($rest:tt)*) => { + bitfield_bitrange!(struct $name(MSB0 [$t])); + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); no default BitRange; impl Debug; $($rest:tt)*) => { + impl $crate::fmt::Debug for $name { + bitfield_debug!{struct $name; $($rest)*} + } + + bitfield!{$(#[$attribute])* ($($vis)*) struct $name($t); no default BitRange; $($rest)*} + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); no default BitRange; $($rest:tt)*) => { + $(#[$attribute])* + $($vis)* struct $name(pub $t); + + impl $name { + bitfield_fields!{$t; $($rest)*} + } + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); $($rest:tt)*) => { + bitfield_bitrange!(struct $name($t)); + bitfield!{$(#[$attribute])* ($($vis)*) struct $name($t); no default BitRange; $($rest)*} + }; +} + +#[doc(hidden)] +pub use core::convert::Into; +#[doc(hidden)] +pub use core::fmt; +#[doc(hidden)] +pub use core::mem::size_of; + +/// A trait to get or set ranges of bits. +pub trait BitRange { + /// Get a range of bits. + fn bit_range(&self, msb: usize, lsb: usize) -> T; + /// Set a range of bits. + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T); +} + +/// A trait to get or set a single bit. +/// +/// This trait is implemented for all type that implement `BitRange`. +pub trait Bit { + /// Get a single bit. + fn bit(&self, bit: usize) -> bool; + + /// Set a single bit. + fn set_bit(&mut self, bit: usize, value: bool); +} + +impl> Bit for T { + fn bit(&self, bit: usize) -> bool { + self.bit_range(bit, bit) != 0 + } + fn set_bit(&mut self, bit: usize, value: bool) { + self.set_bit_range(bit, bit, value as u8); + } +} + +macro_rules! impl_bitrange_for_u { + ($t:ty, $bitrange_ty:ty) => { + impl BitRange<$bitrange_ty> for $t { + #[inline] + #[allow(unknown_lints)] + #[allow(cast_lossless)] + fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { + let bit_len = size_of::<$t>()*8; + let result_bit_len = size_of::<$bitrange_ty>()*8; + let result = ((*self << (bit_len - msb - 1)) >> (bit_len - msb - 1 + lsb)) + as $bitrange_ty; + result << (result_bit_len - (msb - lsb + 1)) >> (result_bit_len - (msb - lsb + 1)) + } + + #[inline] + #[allow(unknown_lints)] + #[allow(cast_lossless)] + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { + let bit_len = size_of::<$t>()*8; + let mask: $t = !(0 as $t) + << (bit_len - msb - 1) + >> (bit_len - msb - 1 + lsb) + << (lsb); + *self &= !mask; + *self |= (value as $t << lsb) & mask; + } + } + } +} + +macro_rules! impl_bitrange_for_u_combinations { +((),($($bitrange_ty:ty),*)) => { + +}; +(($t:ty),($($bitrange_ty:ty),*)) => { + $(impl_bitrange_for_u!{$t, $bitrange_ty})* +}; + (($t_head:ty, $($t_rest:ty),*),($($bitrange_ty:ty),*)) => { + impl_bitrange_for_u_combinations!{($t_head), ($($bitrange_ty),*)} + impl_bitrange_for_u_combinations!{($($t_rest),*), ($($bitrange_ty),*)} + }; +} + +impl_bitrange_for_u_combinations! {(u8, u16, u32, u64, u128), (u8, u16, u32, u64, u128)} +impl_bitrange_for_u_combinations! {(u8, u16, u32, u64, u128), (i8, i16, i32, i64, i128)} + +// Same as std::stringify but callable from local_inner_macros macros defined inside +// this crate. +#[macro_export] +#[doc(hidden)] +macro_rules! __bitfield_stringify { + ($s:ident) => { + stringify!($s) + }; +} + +// Same as std::debug_assert but callable from local_inner_macros macros defined inside +// this crate. +#[macro_export] +#[doc(hidden)] +macro_rules! __bitfield_debug_assert { + ($e:expr) => { + debug_assert!($e) + }; +} diff --git a/src/rust/vendor/bitfield/tests/lib.rs b/src/rust/vendor/bitfield/tests/lib.rs new file mode 100644 index 000000000..f762367f3 --- /dev/null +++ b/src/rust/vendor/bitfield/tests/lib.rs @@ -0,0 +1,1105 @@ +#![recursion_limit = "128"] + +#[macro_use] +extern crate bitfield; + +// We use a constant to make sure bits positions don't need to be literals but +// can also be constants or expressions. +const THREE: usize = 3; + +#[derive(Copy, Clone, Debug)] +pub struct Foo(u16); +impl From for Foo { + fn from(value: u8) -> Foo { + Foo(u16::from(value)) + } +} + +impl From for u8 { + fn from(value: Foo) -> u8 { + value.0 as u8 + } +} + +bitfield! { + #[derive(Copy, Clone)] + /// documentation comments also work! + struct FooBar(u32); + impl Debug; + foo1, set_foo1: 0, 0; + u8; + foo2, set_foo2: 31, 31; + foo3, set_foo3: THREE, 0; + // We make sure attributes are applied to fields. If attributes were not + // applied, the compilation would fail with a `duplicate definition` + // error. + #[cfg(not(test))] + foo3, set_foo3: 3, 0; + u16, foo4, set_foo4: 31, 28; + foo5, set_foo5: 0, 0, 32; + u32; + foo6, set_foo6: 5, THREE, THREE; + getter_only, _: 3, 1; + _, setter_only: 2*2, 2; + getter_only_array, _: 5, 3, 3; + _, setter_only_array: 2*THREE, 4, 3; + all_bits, set_all_bits: 31, 0; + single_bit, set_single_bit: 3; + u8, into Foo, into_foo1, set_into_foo1: 31, 31; + pub u8, into Foo, into_foo2, set_into_foo2: 31, 31; + u8, from into Foo, from_foo1, set_from_foo1: 31, 31; + u8, from into Foo, _, set_from_foo2: 31, 31; + u8; + into Foo, into_foo3, set_into_foo3: 31, 31; + pub into Foo, into_foo4, set_into_foo4: 31, 31; + into Foo, _, set_into_foo5: 31, 31; + into Foo, into_foo6, _: 29, 29, 3; + from into Foo, from_foo3, set_from_foo3: 31, 31; + from into Foo, _, set_from_foo4: 31, 31; + from into Foo, from_foo5, set_from_foo5: 29, 29, 3; + from into Foo, from_foo6, _: 31, 31; + i8; + signed_single_bit, set_signed_single_bit: 0, 0; + signed_two_bits, set_signed_two_bits: 1, 0; + signed_eight_bits, set_signed_eight_bits: 7, 0; + signed_eight_bits_unaligned, set_signed_eight_bits_unaligned: 8, 1; + u128, u128_getter, set_u128: 8, 1; + i128, i128_getter, set_i128: 8, 1; +} + +impl FooBar { + bitfield_fields! { + // Boolean field don't need a type + foo7, _: 1; + } + + bitfield_fields! { + // If all fields have a type, we don't need to specify a default type + u8, foo8,_: 1, 0; + u32, foo9, _: 2, 0; + } + + bitfield_fields! { + // We can still set a default type + u16; + foo10, _: 2, 0; + u32, foo11, _: 2, 0; + foo12, _: 2, 0; + } + + // Check if an empty bitfield_fields compiles without errors. + bitfield_fields! {} +} + +#[test] +fn test_single_bit() { + let mut fb = FooBar(0); + + fb.set_foo1(1); + assert_eq!(0x1, fb.0); + assert_eq!(0x1, fb.foo1()); + assert_eq!(0x0, fb.foo2()); + assert_eq!(false, fb.single_bit()); + assert_eq!(-1, fb.signed_single_bit()); + + fb.set_foo2(1); + assert_eq!(0x8000_0001, fb.0); + assert_eq!(0x1, fb.foo1()); + assert_eq!(0x1, fb.foo2()); + assert_eq!(false, fb.single_bit()); + assert_eq!(-1, fb.signed_single_bit()); + + fb.set_foo1(0); + assert_eq!(0x8000_0000, fb.0); + assert_eq!(0x0, fb.foo1()); + assert_eq!(0x1, fb.foo2()); + assert_eq!(false, fb.single_bit()); + assert_eq!(0, fb.signed_single_bit()); + + fb.set_single_bit(true); + assert_eq!(0x8000_0008, fb.0); + assert_eq!(0x0, fb.foo1()); + assert_eq!(0x1, fb.foo2()); + assert_eq!(true, fb.single_bit()); + assert_eq!(0, fb.signed_single_bit()); + + fb.set_signed_single_bit(-1); + assert_eq!(0x8000_0009, fb.0); + assert_eq!(0x1, fb.foo1()); + assert_eq!(0x1, fb.foo2()); + assert_eq!(true, fb.single_bit()); + assert_eq!(-1, fb.signed_single_bit()); +} + +#[test] +fn test_single_bit_plus_garbage() { + let mut fb = FooBar(0); + + fb.set_foo1(0b10); + assert_eq!(0x0, fb.0); + assert_eq!(0x0, fb.foo1()); + assert_eq!(0x0, fb.foo2()); + + fb.set_foo1(0b11); + assert_eq!(0x1, fb.0); + assert_eq!(0x1, fb.foo1()); + assert_eq!(0x0, fb.foo2()); +} + +#[test] +fn test_multiple_bit() { + let mut fb = FooBar(0); + + fb.set_foo3(0x0F); + assert_eq!(0xF, fb.0); + assert_eq!(0xF, fb.foo3()); + assert_eq!(0x0, fb.foo4()); + + fb.set_foo4(0x0F); + assert_eq!(0xF000_000F, fb.0); + assert_eq!(0xF, fb.foo3()); + assert_eq!(0xF, fb.foo4()); + + fb.set_foo3(0); + assert_eq!(0xF000_0000, fb.0); + assert_eq!(0x0, fb.foo3()); + assert_eq!(0xF, fb.foo4()); + + fb.set_foo3(0xA); + assert_eq!(0xF000_000A, fb.0); + assert_eq!(0xA, fb.foo3()); + assert_eq!(0xF, fb.foo4()); +} + +#[test] +fn test_getter_setter_only() { + let mut fb = FooBar(0); + fb.setter_only(0x7); + assert_eq!(0x1C, fb.0); + assert_eq!(0x6, fb.getter_only()); +} + +#[test] +fn test_array_field1() { + let mut fb = FooBar(0); + + fb.set_foo5(0, 1); + assert_eq!(0x1, fb.0); + assert_eq!(1, fb.foo5(0)); + + fb.set_foo5(0, 0); + assert_eq!(0x0, fb.0); + assert_eq!(0, fb.foo5(0)); + + fb.set_foo5(0, 1); + fb.set_foo5(6, 1); + fb.set_foo5(31, 1); + assert_eq!(0x8000_0041, fb.0); + assert_eq!(1, fb.foo5(0)); + assert_eq!(1, fb.foo5(6)); + assert_eq!(1, fb.foo5(31)); + assert_eq!(0, fb.foo5(1)); + assert_eq!(0, fb.foo5(5)); + assert_eq!(0, fb.foo5(7)); + assert_eq!(0, fb.foo5(30)); +} + +#[test] +fn test_array_field2() { + let mut fb = FooBar(0); + + fb.set_foo6(0, 1); + assert_eq!(0x8, fb.0); + assert_eq!(1, fb.foo6(0)); + assert_eq!(0, fb.foo6(1)); + assert_eq!(0, fb.foo6(2)); + + fb.set_foo6(0, 7); + assert_eq!(0x38, fb.0); + assert_eq!(7, fb.foo6(0)); + assert_eq!(0, fb.foo6(1)); + assert_eq!(0, fb.foo6(2)); + + fb.set_foo6(2, 7); + assert_eq!(0xE38, fb.0); + assert_eq!(7, fb.foo6(0)); + assert_eq!(0, fb.foo6(1)); + assert_eq!(7, fb.foo6(2)); + + fb.set_foo6(0, 0); + assert_eq!(0xE00, fb.0); + assert_eq!(0, fb.foo6(0)); + assert_eq!(0, fb.foo6(1)); + assert_eq!(7, fb.foo6(2)); +} + +#[allow(unknown_lints)] +#[allow(identity_op)] +#[allow(erasing_op)] +#[test] +fn test_setter_only_array() { + let mut fb = FooBar(0); + + fb.setter_only_array(0, 0); + assert_eq!(0x0, fb.0); + + fb.setter_only_array(0, 0b111); + assert_eq!(0b111 << (4 + 0 * 2), fb.0); + + fb.setter_only_array(0, 0); + fb.setter_only_array(1, 0b111); + assert_eq!(0b111 << (4 + 1 * 3), fb.0); + + fb.setter_only_array(1, 0); + fb.setter_only_array(2, 0b111); + assert_eq!(0b111 << (4 + 2 * 3), fb.0); +} + +#[test] +fn test_getter_only_array() { + let mut fb = FooBar(0); + + assert_eq!(0, fb.getter_only_array(0)); + assert_eq!(0, fb.getter_only_array(1)); + assert_eq!(0, fb.getter_only_array(2)); + + fb.0 = !(0x1FF << 3); + assert_eq!(0, fb.getter_only_array(0)); + assert_eq!(0, fb.getter_only_array(1)); + assert_eq!(0, fb.getter_only_array(2)); + + fb.0 = 0xF << 3; + assert_eq!(0b111, fb.getter_only_array(0)); + assert_eq!(0b001, fb.getter_only_array(1)); + assert_eq!(0, fb.getter_only_array(2)); + + fb.0 = 0xF << 6; + assert_eq!(0, fb.getter_only_array(0)); + assert_eq!(0b111, fb.getter_only_array(1)); + assert_eq!(0b001, fb.getter_only_array(2)); + + fb.0 = 0xF << 8; + assert_eq!(0, fb.getter_only_array(0)); + assert_eq!(0b100, fb.getter_only_array(1)); + assert_eq!(0b111, fb.getter_only_array(2)); + + fb.0 = 0b101_010_110 << 3; + assert_eq!(0b110, fb.getter_only_array(0)); + assert_eq!(0b010, fb.getter_only_array(1)); + assert_eq!(0b101, fb.getter_only_array(2)); +} + +#[test] +fn test_signed() { + let mut fb = FooBar(0); + + assert_eq!(0, fb.signed_two_bits()); + assert_eq!(0, fb.signed_eight_bits()); + assert_eq!(0, fb.signed_eight_bits_unaligned()); + + fb.set_signed_two_bits(-2); + assert_eq!(0b10, fb.0); + assert_eq!(-2, fb.signed_two_bits()); + assert_eq!(2, fb.signed_eight_bits()); + assert_eq!(1, fb.signed_eight_bits_unaligned()); + + fb.set_signed_two_bits(-1); + assert_eq!(0b11, fb.0); + assert_eq!(-1, fb.signed_two_bits()); + assert_eq!(3, fb.signed_eight_bits()); + assert_eq!(1, fb.signed_eight_bits_unaligned()); + + fb.set_signed_two_bits(0); + assert_eq!(0, fb.0); + assert_eq!(0, fb.signed_two_bits()); + assert_eq!(0, fb.signed_eight_bits()); + assert_eq!(0, fb.signed_eight_bits_unaligned()); + + fb.set_signed_two_bits(1); + assert_eq!(1, fb.0); + assert_eq!(1, fb.signed_two_bits()); + assert_eq!(1, fb.signed_eight_bits()); + assert_eq!(0, fb.signed_eight_bits_unaligned()); + + fb.set_signed_eight_bits(0); + assert_eq!(0, fb.0); + assert_eq!(0, fb.signed_two_bits()); + assert_eq!(0, fb.signed_eight_bits()); + assert_eq!(0, fb.signed_eight_bits_unaligned()); + + fb.set_signed_eight_bits(-1); + assert_eq!(0xFF, fb.0); + assert_eq!(-1, fb.signed_two_bits()); + assert_eq!(-1, fb.signed_eight_bits()); + assert_eq!(127, fb.signed_eight_bits_unaligned()); + + fb.set_signed_eight_bits(-128); + assert_eq!(0x80, fb.0); + assert_eq!(0, fb.signed_two_bits()); + assert_eq!(-128, fb.signed_eight_bits()); + assert_eq!(64, fb.signed_eight_bits_unaligned()); + + fb.set_signed_eight_bits(127); + assert_eq!(0x7F, fb.0); + assert_eq!(-1, fb.signed_two_bits()); + assert_eq!(127, fb.signed_eight_bits()); + assert_eq!(63, fb.signed_eight_bits_unaligned()); + + fb.set_signed_eight_bits_unaligned(0); + assert_eq!(1, fb.0); + assert_eq!(1, fb.signed_two_bits()); + assert_eq!(1, fb.signed_eight_bits()); + assert_eq!(0, fb.signed_eight_bits_unaligned()); + + fb.set_signed_eight_bits(0); + fb.set_signed_eight_bits_unaligned(-1); + assert_eq!(0x1FE, fb.0); + assert_eq!(-2, fb.signed_two_bits()); + assert_eq!(-2, fb.signed_eight_bits()); + assert_eq!(-1, fb.signed_eight_bits_unaligned()); + + fb.set_signed_eight_bits_unaligned(-128); + assert_eq!(0x100, fb.0); + assert_eq!(0, fb.signed_two_bits()); + assert_eq!(0, fb.signed_eight_bits()); + assert_eq!(-128, fb.signed_eight_bits_unaligned()); + fb.set_signed_eight_bits_unaligned(127); + assert_eq!(0xFE, fb.0); + assert_eq!(-2, fb.signed_two_bits()); + assert_eq!(-2, fb.signed_eight_bits()); + assert_eq!(127, fb.signed_eight_bits_unaligned()); +} + +#[test] +fn test_field_type() { + let fb = FooBar(0); + let _: u32 = fb.foo1(); + let _: u8 = fb.foo2(); + let _: u8 = fb.foo3(); + let _: u16 = fb.foo4(); + let _: u8 = fb.foo5(0); + let _: u32 = fb.foo6(0); + + let _: bool = fb.foo7(); + let _: u8 = fb.foo8(); + let _: u32 = fb.foo9(); + let _: u16 = fb.foo10(); + let _: u32 = fb.foo11(); + let _: u16 = fb.foo12(); + + let _: Foo = fb.into_foo1(); + let _: Foo = fb.into_foo2(); + let _: Foo = fb.into_foo3(); + let _: Foo = fb.into_foo4(); + let _: Foo = fb.into_foo6(0); + + let _: Foo = fb.from_foo1(); + let _: Foo = fb.from_foo3(); + let _: Foo = fb.from_foo5(0); + + let _: i8 = fb.signed_single_bit(); + let _: i8 = fb.signed_two_bits(); + let _: i8 = fb.signed_eight_bits(); + let _: i8 = fb.signed_eight_bits_unaligned(); + + let _: u128 = fb.u128_getter(); + let _: i128 = fb.i128_getter(); +} + +#[test] +fn test_into_setter() { + let mut fb = FooBar(0); + + // We just check that the parameter type is correct + fb.set_into_foo1(0u8); + fb.set_into_foo2(0u8); + fb.set_into_foo3(0u8); + fb.set_into_foo4(0u8); +} + +#[test] +fn test_from_setter() { + let mut fb = FooBar(0); + assert_eq!(0, fb.0); + + fb.set_from_foo1(Foo(1)); + assert_eq!(1 << 31, fb.0); + fb.set_from_foo1(Foo(0)); + assert_eq!(0, fb.0); + + fb.set_from_foo2(Foo(1)); + assert_eq!(1 << 31, fb.0); + fb.set_from_foo2(Foo(0)); + assert_eq!(0, fb.0); + + fb.set_from_foo3(Foo(1)); + assert_eq!(1 << 31, fb.0); + fb.set_from_foo3(Foo(0)); + assert_eq!(0, fb.0); + + fb.set_from_foo4(Foo(1)); + assert_eq!(1 << 31, fb.0); + fb.set_from_foo4(Foo(0)); + assert_eq!(0, fb.0); + + fb.set_from_foo5(1, Foo(1)); + assert_eq!(1 << 30, fb.0); +} + +#[test] +fn test_all_bits() { + let mut fb = FooBar(0); + + assert_eq!(0, fb.all_bits()); + + fb.set_all_bits(!0u32); + assert_eq!(!0u32, fb.0); + assert_eq!(!0u32, fb.all_bits()); + + fb.0 = 0x8000_0001; + assert_eq!(0x8000_0001, fb.all_bits()); +} + +#[test] +fn test_is_copy() { + let a = FooBar(0); + let _b = a; + let _c = a; +} + +#[test] +fn test_debug() { + let fb = FooBar(1_234_567_890); + let expected = "FooBar { .0: 1234567890, foo1: 0, foo2: 0, foo3: 2, foo3: 2, foo4: 4, foo5: [0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0], foo6: [2, 3, 1], getter_only: 1, getter_only_array: [2, 3, 1], all_bits: 1234567890, single_bit: false, into_foo1: Foo(0), into_foo2: Foo(0), from_foo1: Foo(0), into_foo3: Foo(0), into_foo4: Foo(0), into_foo6: [Foo(0), Foo(1), Foo(0)], from_foo3: Foo(0), from_foo5: [Foo(0), Foo(1), Foo(0)], from_foo6: Foo(0), signed_single_bit: 0, signed_two_bits: -2, signed_eight_bits: -46, signed_eight_bits_unaligned: 105, u128_getter: 105, i128_getter: 105 }"; + assert_eq!(expected, format!("{:?}", fb)) +} + +bitfield! { + struct ArrayBitfield([u8]); + u32; + foo1, set_foo1: 0, 0; + foo2, set_foo2: 7, 0; + foo3, set_foo3: 8, 1; + foo4, set_foo4: 19, 4; + i32; + signed_foo1, set_signed_foo1: 0, 0; + signed_foo2, set_signed_foo2: 7, 0; + signed_foo3, set_signed_foo3: 8, 1; + signed_foo4, set_signed_foo4: 19, 4; + u128, u128_getter, set_u128: 19, 4; +} + +#[test] +fn test_arraybitfield() { + let mut ab = ArrayBitfield([0; 3]); + + assert_eq!(0u32, ab.foo1()); + assert_eq!(0u32, ab.foo2()); + assert_eq!(0u32, ab.foo3()); + assert_eq!(0u32, ab.foo4()); + assert_eq!(0i32, ab.signed_foo1()); + assert_eq!(0i32, ab.signed_foo2()); + assert_eq!(0i32, ab.signed_foo3()); + assert_eq!(0i32, ab.signed_foo4()); + assert_eq!(0u128, ab.u128_getter()); + + ab.set_foo1(1); + assert_eq!([1, 0, 0], ab.0); + assert_eq!(1, ab.foo1()); + assert_eq!(1, ab.foo2()); + assert_eq!(0, ab.foo3()); + assert_eq!(0, ab.foo4()); + assert_eq!(-1, ab.signed_foo1()); + assert_eq!(1, ab.signed_foo2()); + assert_eq!(0, ab.signed_foo3()); + assert_eq!(0, ab.signed_foo4()); + assert_eq!(0, ab.u128_getter()); + + ab.set_foo1(0); + ab.set_foo2(0xFF); + assert_eq!([0xFF, 0, 0], ab.0); + assert_eq!(1, ab.foo1()); + assert_eq!(0xFF, ab.foo2()); + assert_eq!(0x7F, ab.foo3()); + assert_eq!(0x0F, ab.foo4()); + assert_eq!(-1, ab.signed_foo1()); + assert_eq!(-1, ab.signed_foo2()); + assert_eq!(127, ab.signed_foo3()); + assert_eq!(0x0F, ab.signed_foo4()); + assert_eq!(0x0F, ab.u128_getter()); + + ab.set_foo2(0); + ab.set_foo3(0xFF); + assert_eq!([0xFE, 0x01, 0], ab.0); + assert_eq!(0, ab.foo1()); + assert_eq!(0xFE, ab.foo2()); + assert_eq!(0xFF, ab.foo3()); + assert_eq!(0x1F, ab.foo4()); + assert_eq!(0, ab.signed_foo1()); + assert_eq!(-2, ab.signed_foo2()); + assert_eq!(-1, ab.signed_foo3()); + assert_eq!(0x1F, ab.signed_foo4()); + assert_eq!(0x1F, ab.u128_getter()); + + ab.set_foo3(0); + ab.set_foo4(0xFFFF); + assert_eq!([0xF0, 0xFF, 0x0F], ab.0); + assert_eq!(0, ab.foo1()); + assert_eq!(0xF0, ab.foo2()); + assert_eq!(0xF8, ab.foo3()); + assert_eq!(0xFFFF, ab.foo4()); + assert_eq!(0, ab.signed_foo1()); + assert_eq!(-16, ab.signed_foo2()); + assert_eq!(-8, ab.signed_foo3()); + assert_eq!(-1, ab.signed_foo4()); + assert_eq!(0xFFFF, ab.u128_getter()); + + ab.set_foo4(0x0); + ab.set_signed_foo1(0); + assert_eq!([0x00, 0x00, 0x00], ab.0); + + ab.set_signed_foo1(-1); + assert_eq!([0x01, 0x00, 0x00], ab.0); + + ab.set_signed_foo1(0); + ab.set_signed_foo2(127); + assert_eq!([0x7F, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(-128); + assert_eq!([0x80, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(1); + assert_eq!([0x01, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(-1); + assert_eq!([0xFF, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(0); + ab.set_signed_foo3(127); + assert_eq!([0xFE, 0x00, 0x00], ab.0); + + ab.set_signed_foo3(-1); + assert_eq!([0xFE, 0x01, 0x00], ab.0); + + ab.set_signed_foo3(0); + ab.set_signed_foo4(-1); + assert_eq!([0xF0, 0xFF, 0x0F], ab.0); + + ab.set_signed_foo4(0); + ab.set_u128(0xFFFF); + assert_eq!([0xF0, 0xFF, 0x0F], ab.0); +} + +#[test] +fn test_arraybitfield2() { + // Check that the macro can be called from a function. + bitfield! { + struct ArrayBitfield2([u16]); + impl Debug; + u32; + foo1, set_foo1: 0, 0; + foo2, set_foo2: 7, 0; + foo3, set_foo3: 8, 1; + foo4, set_foo4: 20, 4; + } + let mut ab = ArrayBitfield2([0; 2]); + + assert_eq!(0, ab.foo1()); + assert_eq!(0, ab.foo2()); + assert_eq!(0, ab.foo3()); + assert_eq!(0, ab.foo4()); + + ab.set_foo1(1); + assert_eq!([1, 0], ab.0); + assert_eq!(1, ab.foo1()); + assert_eq!(1, ab.foo2()); + assert_eq!(0, ab.foo3()); + assert_eq!(0, ab.foo4()); + + ab.set_foo1(0); + ab.set_foo2(0xFF); + assert_eq!([0xFF, 0], ab.0); + assert_eq!(1, ab.foo1()); + assert_eq!(0xFF, ab.foo2()); + assert_eq!(0x7F, ab.foo3()); + assert_eq!(0x0F, ab.foo4()); + + ab.set_foo2(0); + ab.set_foo3(0xFF); + assert_eq!([0x1FE, 0x0], ab.0); + assert_eq!(0, ab.foo1()); + assert_eq!(0xFE, ab.foo2()); + assert_eq!(0xFF, ab.foo3()); + assert_eq!(0x1F, ab.foo4()); + + ab.set_foo3(0); + ab.set_foo4(0xFFFF); + assert_eq!([0xFFF0, 0xF], ab.0); + assert_eq!(0, ab.foo1()); + assert_eq!(0xF0, ab.foo2()); + assert_eq!(0xF8, ab.foo3()); + assert_eq!(0xFFFF, ab.foo4()); +} + +bitfield! { + struct ArrayBitfieldMsb0(MSB0 [u8]); + impl Debug; + u32; + foo1, set_foo1: 0, 0; + foo2, set_foo2: 7, 0; + foo3, set_foo3: 8, 1; + foo4, set_foo4: 19, 4; + i32; + signed_foo1, set_signed_foo1: 0, 0; + signed_foo2, set_signed_foo2: 7, 0; + signed_foo3, set_signed_foo3: 8, 1; + signed_foo4, set_signed_foo4: 19, 4; +} + +#[test] +fn test_arraybitfield_msb0() { + let mut ab = ArrayBitfieldMsb0([0; 3]); + + assert_eq!(0, ab.foo1()); + assert_eq!(0, ab.foo2()); + assert_eq!(0, ab.foo3()); + assert_eq!(0, ab.foo4()); + assert_eq!(0, ab.signed_foo1()); + assert_eq!(0, ab.signed_foo2()); + assert_eq!(0, ab.signed_foo3()); + assert_eq!(0, ab.signed_foo4()); + + ab.set_foo1(1); + assert_eq!([0b1000_0000, 0, 0], ab.0); + assert_eq!(1, ab.foo1()); + assert_eq!(0b1000_0000, ab.foo2()); + assert_eq!(0, ab.foo3()); + assert_eq!(0, ab.foo4()); + assert_eq!(-1, ab.signed_foo1()); + assert_eq!(-128, ab.signed_foo2()); + assert_eq!(0, ab.signed_foo3()); + assert_eq!(0, ab.signed_foo4()); + + ab.set_foo1(0); + ab.set_foo2(0xFF); + assert_eq!([0b1111_1111, 0, 0], ab.0); + assert_eq!(1, ab.foo1()); + assert_eq!(0b1111_1111, ab.foo2()); + assert_eq!(0b1111_1110, ab.foo3()); + assert_eq!(0b1111_0000_0000_0000, ab.foo4()); + assert_eq!(-1, ab.signed_foo1()); + assert_eq!(-1, ab.signed_foo2()); + assert_eq!(-2, ab.signed_foo3()); + assert_eq!(-4096, ab.signed_foo4()); + + ab.set_foo2(0); + ab.set_foo3(0xFF); + assert_eq!([0b0111_1111, 0b1000_0000, 0], ab.0); + assert_eq!(0, ab.foo1()); + assert_eq!(0b0111_1111, ab.foo2()); + assert_eq!(0xFF, ab.foo3()); + assert_eq!(0b1111_1000_0000_0000, ab.foo4()); + assert_eq!(0, ab.signed_foo1()); + assert_eq!(127, ab.signed_foo2()); + assert_eq!(-1, ab.signed_foo3()); + assert_eq!(-2048, ab.signed_foo4()); + + ab.set_foo3(0); + ab.set_foo4(0xFFFF); + assert_eq!([0x0F, 0xFF, 0xF0], ab.0); + assert_eq!(0, ab.foo1()); + assert_eq!(0x0F, ab.foo2()); + assert_eq!(0b0001_1111, ab.foo3()); + assert_eq!(0xFFFF, ab.foo4()); + assert_eq!(0, ab.signed_foo1()); + assert_eq!(0x0F, ab.signed_foo2()); + assert_eq!(0b0001_1111, ab.signed_foo3()); + assert_eq!(-1, ab.signed_foo4()); + + ab.set_foo4(0x0); + ab.set_signed_foo1(0); + assert_eq!([0x00, 0x00, 0x00], ab.0); + + ab.set_signed_foo1(-1); + assert_eq!([0b1000_0000, 0x00, 0x00], ab.0); + + ab.set_signed_foo1(0); + ab.set_signed_foo2(127); + assert_eq!([0x7F, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(-128); + assert_eq!([0x80, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(1); + assert_eq!([0x01, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(-1); + assert_eq!([0xFF, 0x00, 0x00], ab.0); + + ab.set_signed_foo2(0); + ab.set_signed_foo3(127); + assert_eq!([0b0011_1111, 0b1000_0000, 0], ab.0); + + ab.set_signed_foo3(-1); + assert_eq!([0b0111_1111, 0b1000_0000, 0], ab.0); + + ab.set_signed_foo3(0); + ab.set_signed_foo4(-1); + assert_eq!([0x0F, 0xFF, 0xF0], ab.0); +} + +mod some_module { + bitfield! { + pub struct PubBitFieldInAModule(u32); + impl Debug; + /// Attribute works on pub fields + pub field1, set_field1: 1; + pub field2, _: 1; + pub _, set_field3: 1; + pub u16, field4, set_field4: 1; + /// Check if multiple attributes are applied + #[cfg(not(test))] + pub u16, field4, set_field4: 1; + pub u16, _, set_field5: 1; + pub u16, field6, _: 1; + pub field7, set_field7: 1; + pub field8, set_field8: 1, 1; + #[cfg(not(test))] + /// And make sure not only the last attributes is applied + pub field8, set_field8: 1, 1; + pub field9, set_field9: 1, 1, 1; + pub u32, field10, set_field10: 1; + pub u32, field11, set_field11: 1, 1; + pub u32, field12, set_field12: 1, 1, 1; + } + +} + +#[test] +fn struct_can_be_public() { + let _ = some_module::PubBitFieldInAModule(0); +} +#[test] +fn field_can_be_public() { + let mut a = some_module::PubBitFieldInAModule(0); + let _ = a.field1(); + a.set_field1(true); + let _ = a.field2(); + a.set_field3(true); + let _ = a.field4(); + a.set_field4(true); + a.set_field5(true); + let _ = a.field6(); + let _ = a.field7(); + a.set_field7(true); + let _ = a.field8(); + a.set_field8(0); + let _ = a.field9(0); + a.set_field9(0, 0); + let _ = a.field10(); + a.set_field10(true); + let _ = a.field11(); + a.set_field11(0); + let _ = a.field12(0); + a.set_field12(0, 0); +} + +// Everything in this module is to make sure that its possible to specify types +// in most of the possible ways. +#[allow(dead_code)] +mod test_types { + use bitfield::BitRange; + use std; + use std::sync::atomic::{self, AtomicUsize}; + + struct Foo; + + impl Foo { + bitfield_fields! { + std::sync::atomic::AtomicUsize, field1, set_field1: 0, 0; + std::sync::atomic::AtomicUsize; + field2, set_field2: 0, 0; + ::std::sync::atomic::AtomicUsize, field3, set_field3: 0, 0; + ::std::sync::atomic::AtomicUsize; + field4, set_field4: 0, 0; + atomic::AtomicUsize, field5, set_field5: 0, 0; + atomic::AtomicUsize; + field6, set_field6: 0, 0; + AtomicUsize, field7, set_field7: 0, 0; + AtomicUsize; + field8, set_field8: 0, 0; + Vec, field9, set_field9: 0, 0; + Vec; + field10, set_field10: 0, 0; + Vec<::std::sync::atomic::AtomicUsize>, field11, set_field11: 0, 0; + Vec<::std::sync::atomic::AtomicUsize>; + field12, set_field12: 0, 0; + Vec, field13, set_field13: 0, 0; + Vec; + field14, set_field14: 0, 0; + Vec, field15, set_field15: 0, 0; + Vec; + field16, set_field16: 0, 0; + &str, field17, set_field17: 0, 0; + &str; + field18, set_field18: 0, 0; + &'static str, field19, set_field19: 0, 0; + &'static str; + field20, set_field20: 0, 0; + } + } + + impl BitRange for Foo { + fn bit_range(&self, _msb: usize, _lsb: usize) -> AtomicUsize { + AtomicUsize::new(0) + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: AtomicUsize) {} + } + + impl BitRange> for Foo { + fn bit_range(&self, _msb: usize, _lsb: usize) -> Vec { + vec![AtomicUsize::new(0)] + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: Vec) {} + } + + impl<'a> BitRange<&'a str> for Foo { + fn bit_range(&self, _msb: usize, _lsb: usize) -> &'a str { + "" + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: &'a str) {} + } + + #[test] + fn test_field_type() { + let test = Foo; + let _: AtomicUsize = test.field1(); + let _: AtomicUsize = test.field2(); + let _: AtomicUsize = test.field3(); + let _: AtomicUsize = test.field4(); + let _: AtomicUsize = test.field5(); + let _: AtomicUsize = test.field6(); + let _: AtomicUsize = test.field7(); + let _: AtomicUsize = test.field8(); + let _: Vec = test.field9(); + let _: Vec = test.field10(); + let _: Vec = test.field11(); + let _: Vec = test.field12(); + let _: Vec = test.field13(); + let _: Vec = test.field14(); + let _: Vec = test.field15(); + let _: Vec = test.field16(); + let _: &str = test.field17(); + let _: &str = test.field18(); + let _: &'static str = test.field19(); + let _: &'static str = test.field20(); + } +} + +#[allow(dead_code)] +mod test_no_default_bitrange { + use bitfield::BitRange; + use std::fmt::Debug; + use std::fmt::Error; + use std::fmt::Formatter; + bitfield! { + #[derive(Eq, PartialEq)] + pub struct BitField1(u16); + no default BitRange; + impl Debug; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 2; + } + + impl BitRange for BitField1 { + fn bit_range(&self, msb: usize, lsb: usize) -> u8 { + (msb + lsb) as u8 + } + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: u8) { + self.0 = msb as u16 + lsb as u16 + u16::from(value) + } + } + + #[allow(unknown_lints)] + #[allow(identity_op)] + #[test] + fn custom_bitrange_implementation_is_used() { + let mut bf = BitField1(0); + assert_eq!(bf.field1(), 10 + 0); + assert_eq!(bf.field2(), 12 + 3); + assert_eq!(bf.field3(), true); + bf.set_field1(42); + assert_eq!(bf, BitField1(10 + 0 + 42)); + } + + bitfield! { + pub struct BitField2(u16); + no default BitRange; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 0; + } + + impl BitRange for BitField2 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + // Make sure Debug wasn't implemented by implementing it. + impl Debug for BitField2 { + fn fmt(&self, _: &mut Formatter) -> Result<(), Error> { + unimplemented!() + } + } + + // Check that we can put `impl Debug` before `no default BitRange` + bitfield! { + pub struct BitField3(u16); + impl Debug; + no default BitRange; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 0; + } + + impl BitRange for BitField3 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + bitfield! { + #[derive(Eq, PartialEq)] + pub struct BitField4([u16]); + no default BitRange; + impl Debug; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 2; + } + + impl BitRange for BitField4 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + bitfield! { + pub struct BitField5([u16]); + no default BitRange; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 0; + } + + impl BitRange for BitField5 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + // Make sure Debug wasn't implemented by implementing it. + impl Debug for BitField5 { + fn fmt(&self, _: &mut Formatter) -> Result<(), Error> { + unimplemented!() + } + } + + // Check that we can put `impl Debug` before `no default BitRange` + bitfield! { + pub struct BitField6([u16]); + impl Debug; + no default BitRange; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 0; + } + + impl BitRange for BitField6 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + bitfield! { + #[derive(Eq, PartialEq)] + pub struct BitField7(MSB0 [u16]); + no default BitRange; + impl Debug; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 2; + } + + impl BitRange for BitField7 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + bitfield! { + pub struct BitField8(MSB0 [u16]); + no default BitRange; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 0; + } + + impl BitRange for BitField8 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + // Make sure Debug wasn't implemented by implementing it. + impl Debug for BitField8 { + fn fmt(&self, _: &mut Formatter) -> Result<(), Error> { + unimplemented!() + } + } + + // Check that we can put `impl Debug` before `no default BitRange` + bitfield! { + pub struct BitField9([u16]); + impl Debug; + no default BitRange; + u8; + field1, set_field1: 10, 0; + pub field2, _ : 12, 3; + field3, set_field3: 0; + } + + impl BitRange for BitField9 { + fn bit_range(&self, _msb: usize, _lsb: usize) -> u8 { + 0 + } + fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u8) {} + } + + #[test] + fn test_debug_is_implemented_with_no_default_bitrange() { + format!("{:?}", BitField1(0)); + format!("{:?}", BitField3(0)); + format!("{:?}", BitField4([0; 1])); + format!("{:?}", BitField6([0; 1])); + format!("{:?}", BitField7([0; 1])); + format!("{:?}", BitField9([0; 1])); + } +} diff --git a/src/rust/vendor/cortex-m/.cargo-checksum.json b/src/rust/vendor/cortex-m/.cargo-checksum.json new file mode 100644 index 000000000..373e91981 --- /dev/null +++ b/src/rust/vendor/cortex-m/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"0746746ed1d76c49bcb397844b176e7bb14511d56df37a66dc38cea98bcff9e6","CODE_OF_CONDUCT.md":"3746a267d008534cec6d7242f09ca6284c5d37e48306531b878461e6c4d33fee","Cargo.toml":"e50cf067b659be75f8f927b342d3446243bdcd86a4b10ea4daff819f6d9ddebd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0a633406531735659d570e7903394ec52f7707195a3c4af10279f06eec7acc76","README.md":"2e2e489b55b8506d174782d8587db6708162f82f1fb4c3272746d079e5972837","asm-toolchain":"5479b28f90ce42bbefc9fed083182e0de8eafc1b69f92fbfc5221d766862682f","asm/inline.rs":"6e9605c595d6c8deddcd2bcb1f9f4d270a10492823e82955888be8ce3b553f3b","asm/lib.rs":"8d7eb1aee66e9d8ff8b5ff5d0a8687d6d255d3403b9c238d7b5620a01602d9b5","bin/thumbv6m-none-eabi-lto.a":"4d13ae583b33613b476b8d2dbf435d363ad25a2135388eb5257b132868461535","bin/thumbv6m-none-eabi.a":"b5002ce424d6baf97639ee188f12a9c7152b1dbc90a1b4393556049f8475be54","bin/thumbv7em-none-eabi-lto.a":"a3dd53e4e7a874f9d7d27acb273eaa17ae72222205e939a7dccc4c02ebb7a3ba","bin/thumbv7em-none-eabi.a":"2ae0edab580e3d1c95bedb4bc9a8a646e2b3ea9fa5bf2768d859fb5a30b8741a","bin/thumbv7em-none-eabihf-lto.a":"71d4bd5af31d3933969aee825400ac105f3d3b826abfb968bfa2c8f3658ecd50","bin/thumbv7em-none-eabihf.a":"0ebff8ad140fe35494fb51ed4184ce19ffab41e9ac62af6a5c5c7b0ea26b9e53","bin/thumbv7m-none-eabi-lto.a":"da3ed6ec4b9fc8803336e280cd71524911fee459e2dac88e29d0e82d043b90d7","bin/thumbv7m-none-eabi.a":"3de841b242e33066555fa06e127f01008711ec08728a2f75d525731d04ae442e","bin/thumbv8m.base-none-eabi-lto.a":"73189749f0c42de0990e76ce531621e17370c0dd00940297e6044a622302df38","bin/thumbv8m.base-none-eabi.a":"b2ff0d88db4aa539ead58c1fb37ef3d171d08462b979a8b7c897ef4148119572","bin/thumbv8m.main-none-eabi-lto.a":"12b43c063fcdb33fb57335c5fc2a0c62e2a427a3c6e8727fb2a4437615e2c07d","bin/thumbv8m.main-none-eabi.a":"9217dcbbd3ef909caa39a5ee75684127b4cf4f51447e41027164462e42a33018","bin/thumbv8m.main-none-eabihf-lto.a":"18aae9047b017ad4003e2311d74b0888701b84333ccf4379d09e6890b1799174","bin/thumbv8m.main-none-eabihf.a":"39fdf845895f31e473fc863fbb21f3590237a571dbfb97c66c7190475a615efb","build.rs":"fe2c0bd4cd56adabf5d3912a9810546e6a32708f165d9ad2dcfe0407df092516","src/asm.rs":"079aaf47d696aa1995ddcf5b38f59ed22e8a48967c261d14676d1757308b534a","src/call_asm.rs":"024486575710dc864613c3c2917887ec9527ae2b66cde183b3233f663a9e790b","src/cmse.rs":"9e868ec9ac0a6296b1e9d943478f6343a3f43979c0f068780adf114f52643707","src/critical_section.rs":"2013adbc5289d71c9f5ccb8353fbc47a2df7f7003180be65b6b07b8c948ca684","src/delay.rs":"27f2adeaf9dc924ac16f1fea9da510469e5c4961d9223aab253d95ee3e0af191","src/interrupt.rs":"41d6338784b86d4c4837e3673c5eff26dd35c851962e741c00f7c933a7e8d218","src/itm.rs":"b50d9d6cad2ec4c841d0f3008df93edb378f8038696a9f096763a488d14df53c","src/lib.rs":"079c614ec9e3ba81bb5ab9638f7f465551805555ab41aab04e62f9015d85fe4a","src/macros.rs":"22d8af93ebe59cd9f6e468cf78c8a342c4444d83f263043d3044358811ffec41","src/peripheral/ac.rs":"b6b228637b09f2fa3ac5344a0759cd4fb852782050f252c2c9bd670660b9a768","src/peripheral/cbp.rs":"9a42efc512ac43278a5efd2fb650043a5672be031e7121c748b41ead97ed4e39","src/peripheral/cpuid.rs":"94285da95a2e6a00f09b049f59c9aede6683dab4be4b218d8bd0cd4183e7a746","src/peripheral/dcb.rs":"3c630cc575c93791f1553607565fdc76d91bb990351deedf9de3efa9184eceb0","src/peripheral/dwt.rs":"780a1094958abc2c8c7d8d196c07637eed619c72d010fcf29235b95c0b1abce3","src/peripheral/fpb.rs":"00eba6fae97614a503e9545f95158083f9e02b6b400fab647be1c0e4747293d7","src/peripheral/fpu.rs":"3bb8d5af0cdce5b25a4f9826fa6bddd75c58f4d61745afd9ed49a5d0e849c2f9","src/peripheral/icb.rs":"fcc13f2652ae39035c4b0f04468d19b3e94bfe3b05832eabc60638dcca9842ae","src/peripheral/itm.rs":"f8c8587ffa60f76e4f4fa293322386727ecf491f1b36672258b7e743b6e37a26","src/peripheral/mod.rs":"900f099bbcae804cde74bf8b5bcb9f84e9dde3018f5efe1098768c5b64021b0b","src/peripheral/mpu.rs":"20d36443ae9928cbf9a7d546298b5ce784c3cae3f2f236a8935b227f9fdbdb06","src/peripheral/nvic.rs":"ae9889495edb21d6a4f09ced401b4b21cdfb2c1ac86e593156e462cc42b5794d","src/peripheral/sau.rs":"32fb6816a3f9c81203b23b1803c8f499059a0460e2fa082e44bff3be9936f467","src/peripheral/scb.rs":"fd56eba0edace3b9278f5b26495eedd42926ed7a7dde2dad41273d26f743c8ff","src/peripheral/syst.rs":"267ac1f7e83cfa6fec1c0d651fa6babcfac90ea5254331b49f305ad0b2034711","src/peripheral/test.rs":"0f0a44af38bc78a4d3bf8995d6c79b1ee4fcb3ffb797db1c41a09d361a075828","src/peripheral/tpiu.rs":"88a86ba957ab94a38b08a5486b9a2c6c20e1b116a92f17666f4ab9b2207e63d1","src/prelude.rs":"cb4e3b91223b64a0a1c1301e6b38318f3ba031ba776ad11983444607735a8175","src/register/apsr.rs":"27ff0eda2861162b6103bb9705c37a877811bc2320785a9ab6d1ea566fa0b2cb","src/register/basepri.rs":"283b98d9befce7a1b623599cf5cfcd889425c69af2d136eef3ca7775c6809e9e","src/register/basepri_max.rs":"849f9bb522d6ea348f646930943481506c80be57613abb64f34319f0f58b6f21","src/register/control.rs":"5a666c93a82c1dea29094c7021ebe0e2a5b7dc67dd7aa7f7c923a25c6dabf992","src/register/faultmask.rs":"6a0d06a48790a25836e2c770ddc136ae5c32ce5290e3865526c8a749bf576d5a","src/register/fpscr.rs":"5d09ecb377a0231876570e3a9d95e3e013cc9ad58a338062a7000b66030f0de4","src/register/lr.rs":"02769270d9b096ccf2d9cf9101e51db142c747536e676fc04b64d4494b0a41b5","src/register/mod.rs":"8d452276b5f0751de0be7fa93ae809f4c08ab2b3db5b03210c7a9541716f1c72","src/register/msp.rs":"59a8294f63272ef1bc8b2691de2d7be51171728602733500b9e28bc285df6148","src/register/msplim.rs":"43c7648180cda21da11df04c55ccd3c5d21ec3ae08b5fa5174a0e9239ee31f61","src/register/pc.rs":"2797c309ee2a5780e8849a955dc3abd0063b442d92c878a51ca83543026a678b","src/register/primask.rs":"cfeb772e1bc6fc1ffe8192a201e12d491bdb570881d0575b5a6727876d11a766","src/register/psp.rs":"2898e262cf821b6f0d59633012e06cef0de0ee4aef0dc603000ea78f877b8de0","src/register/psplim.rs":"d4cabb7d7cfca9338e82c51658ae409e501e2fd4ba15e0162eb57e2f55649d67","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"} \ No newline at end of file diff --git a/src/rust/vendor/cortex-m/CHANGELOG.md b/src/rust/vendor/cortex-m/CHANGELOG.md new file mode 100644 index 000000000..ca9609ce9 --- /dev/null +++ b/src/rust/vendor/cortex-m/CHANGELOG.md @@ -0,0 +1,807 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.7.7] - 2023-01-03 + +- Add missing documentation for `critical-section-single-core` feature added + in v0.7.6. + +## [v0.7.6] - 2022-08-12 + +- Added `critical-section-single-core` feature which provides an implementation for the `critical-section` crate for single-core systems, based on disabling all interrupts. (#448) + +## [v0.7.5] - 2022-05-15 + +### Deprecated +- the `ptr()` function on all peripherals register blocks in favor of + the associated constant `PTR` (#386). + +### Changed + +- The `inline-asm` feature no longer requires a nightly Rust compiler, but + does require Rust 1.59 or above. + +### Fixed +- Fixed `singleton!()` statics sometimes ending up in `.data` instead of `.bss` (#364, #380). + (Backported from upcoming 0.8 release). + +## [v0.7.4] - 2021-12-31 + +### Added + +- Added support for additional DWT counters (#349) + - CPI counter + - Exception overhead counter + - LSU counter + - Folded-instruction counter +- Added `DWT.set_cycle_count` (#347). +- Added support for the Cortex-M7 TCM and cache access control registers. + There is a feature `cm7` to enable access to these (#352). +- Add derives for serde, Hash, and PartialOrd to VectActive behind feature + gates for host-platform use (#363). +- Support host platforms besides x86_64 (#369). +- Added `delay::Delay::with_source`, a constructor that lets you specify + the SysTick clock source (#374). + +### Fixed + +- Fix incorrect AIRCR PRIGROUP mask (#338, #339). +- Fix nightly users of inline-asm breaking now that the asm macro is removed + from the prelude (#372). + +### Deprecated + +- `DWT::get_cycle_count` has been deprecated in favor of `DWT::cycle_count`. + This change was made for consistency with the [C-GETTER] convention. (#349) + +[C-GETTER]: https://rust-lang.github.io/api-guidelines/naming.html#c-getter + +## [v0.7.3] - 2021-07-03 + +### Fixed + +- Fixed compilation for native targets on non-x86 host systems (#336, #337). + +### Added + +- The `Delay` struct now offers direct `delay_us()` and `delay_ms()` methods + without having to go through the embedded-hal traits (#344). + +## [v0.7.2] - 2021-03-07 + +### Fixed + +- Fixed a bug where calling `asm::delay()` with an argument of 0 or 1 would + underflow, leading to a very long delay. + +## [v0.7.1] - 2021-01-25 + +### Added + +- New assembly methods `asm::semihosting_syscall`, `asm::bootstrap`, and + `asm::bootload`. + +### Deprecated + +- `msp::write` has been deprecated in favor of `asm::bootstrap`. It was not + possible to use `msp::write` without causing Undefined Behavior, so all + existing users are encouraged to migrate. + +### Fixed + +- Fixed a bug in `asm::delay` which could lead to incorrect codegen and + infinite loops. +- Improved timing guarantees of `asm::delay` on multiple-issue CPU cores. +- Additional compiler fences added to inline assembly where necessary. +- Fixed DWARF debug information in pre-built assembly binaries. + +## [v0.7.0] - 2020-11-09 + +### Added + +- New `InterruptNumber` trait is now required on interrupt arguments to the + various NVIC functions, replacing the previous use of `Nr` from bare-metal. + For backwards compatibility, `InterruptNumber` is implemented for types + which are `Nr + Copy`, but this will be removed in a future version. +- Associated const `PTR` is introduced to Core Peripherals to + eventually replace the existing `ptr()` API. +- A delay driver based on SysTick. +- You can now use LTO to inline assembly calls, even on stable Rust. + See the `asm/lib.rs` documentation for more details. +- Initial ARMv8-M MPU support +- ICTR and ACTLR registers added +- Support for the Security Attribution Unit on ARMv8-M + +### Changed + +- Previously, asm calls without the `inline-asm` feature enabled used pre-built + objects which were built by a GCC compiler, while `inline-asm` enabled the + use of `llvm_asm!` calls. The asm system has been replaced with a new + technique which generates Rust static libs for stable calling, and uses the + new `asm!` macro with `inline-asm`. See the `asm/lib.rs` documentation for + more details. +- Cache enabling now uses an assembly sequence to ensure correctness. +- `ptr()` methods are now `const`. + +### Breaking Changes +- `SCB::invalidate_dcache` and related methods are now unsafe, see #188 +- `Peripherals` struct is now non-exhaustive, so fields may be added in future + non-breaking changes +- Removed `aligned` dependency +- Removed const-fn feature +- Removed previously deprecated APIs + - `NVIC::clear_pending` + - `NVIC::disable` + - `NVIC::enable` + - `NVIC::set_pending` + - `SCB::system_reset` +- Removed `basepri`, `basepri_max`, and `faultmask` registers from thumbv8m.base + +## [v0.6.7] - 2021-01-26 + +### Fixed + +- Fixed missing `peripheral::itm` reexport. + +## [v0.6.6] - 2021-01-26 + +### Fixed + +- Fixed missing ITM reexport on `thumbv8m.base` targets. + +## [v0.6.5] - 2021-01-24 + +### Changed + +- This release is forwards-compatible with cortex-m 0.7, and depends on and + re-exports many types from that version. Both 0.6.5 and 0.7 may co-exist + in a build. + +## [v0.6.4] - 2020-10-26 + +### Changed + +- MSRV bumped to 1.36.0 due to `aligned` dependency. + +### Fixed + +- Drop AT&T syntax from inline asm, which was causing miscompilations with newer versions of the compiler. + +## [v0.6.3] - 2020-07-20 + +### Added + +- Initial Cortex-M Security Extension support for armv8m +- `UDF` intrinsic +- Methods to enable/disable exceptions in SCB + +### Fixed + +- Fix bug in `asm::delay` not updating status clobber flags +- Swapped to `llvm_asm!` to support inline assembly on new nightlies +- Our precompiled assembly routines have additional debug information +- ITM `is_fifo_ready` improved to support armv8 +- Cache enabling moved to pre-built assembly routines to prevent possible + undefined behaviour + +## [v0.6.2] - 2020-01-12 + +### Added + +- Allow writing to the `CONTROL` register via `register::control::write` +- Add `DWT::unlock()` for a safe way to unlock the DWT + +### Deprecation + +- Deprecated incorrectly included registers (`BASPRI`, `BASEPRI_MAX`, `FAULTMASK`) on `thumbv8.base` + +## [v0.6.1] - 2019-08-21 + +### Fixed + +- Better `Debug`, `PartialEq` and `Eq` for more types +- The `delay` function is fixed for Cortex-M0 MCUs + +### Added + +- Static version of `system_reset` as `system_reset2` +- Now uses `links = "cortex-m"` to not link multiple versions of the crate +- Masking of the NVIC is added `NVIC::{mask,unmask}` +- Now Rust 2018 edition +- `{M,P}SPLIM` access is now possible on ARMv8-M + +### Deprecation + +- `system_reset` is deprecated in favor of `sys_reset` + +## [v0.6.0] - 2019-03-12 + +### Fixed + +- Fix numerous registers which were incorrectly included for thumbv6 +- `SHCRS` renamed to `SHCSR` in `SCB` + +### Added + +- Support for ARMv8-M (`thumbv8.base` and `thumbv8.main`) + +- `SCB` gained methods to set and clear `SLEEPONEXIT` bit + +- `NVIC` gained `STIR` register and methods to request an interrupt + +- `DCB` gained methods to check if debugger is attached + +## [v0.5.8] - 2018-10-27 + +### Added + +- `SCB` gained methods to set, clear and check the pending state of the PendSV + exception. + +- `SCB` gained methods to set, clear and check the pending state of the SysTick + exception. + +- `SCB` gained methods to set and get the priority of system handlers like + SVCall and SysTick. + +- `NVIC` gained *static* methods, `pend` and `unpend`, to set and clear the + pending state of interrupts. + +### Changed + +- The `NVIC.{clear,set}_pending` methods have been deprecated in favor of + `NVIC::{unpend,pend}`. + +## [v0.5.7] - 2018-09-06 + +### Added + +- `DCB::enable_trace()` and `DCB::disable_trace()` + +### Changed + +- `iprintln!` no longer depends on `iprint!`. `cortex_m::iprintln!` will work + even if `cortex_m::iprint` has not been imported. + +## [v0.5.6] - 2018-08-27 + +### Fixed + +- Removed duplicated symbols from binary blobs + +- The check-blobs.sh script + +## [v0.5.5] - 2018-08-27 - YANKED + +### Changed + +- This crate no longer depends on `arm-none-eabi-gcc`. + +## [v0.5.4] - 2018-08-11 + +### Added + +- A method to trigger a system reset. See `SCB.system_reset`. + +### Fixed + +- Made the VTOR register (see peripheral::SCB) available on `thumbv6m-none-eabi`. This register is + present on Cortex-M0+, but not on Cortex-M0. + +- Linking with LLD by marking all external assembly functions as `.thumb_func`. See + https://bugs.llvm.org/show_bug.cgi?id=38435 for details. + +## [v0.5.3] - 2018-08-02 + +### Fixed + +- Don't assemble basepri*.s and faultmask.s for ARMv6-M. This fix the build when using `clang` as + the assembler. + +## [v0.5.2] - 2018-05-18 + +### Added + +- `SCB` gained a pair of safe methods to set / clear the DEEPSLEEP bit. + +- `asm::delay`, delay loops whose execution time doesn't depend on the optimization level. + +## [v0.5.1] - 2018-05-13 + +### Added + +- An opt-in `"const-fn"` feature that makes `Mutex.new` constructor into a `const fn`. This feature + requires a nightly toolchain. + +## [v0.5.0] - 2018-05-11 + +### Added + +- `DebugMonitor` and `SecureFault` variants to the `Exception` enumeration. + +- An optional `"inline-asm"` feature + +### Changed + +- [breaking-change] This crate now requires `arm-none-eabi-gcc` to be installed and available in + `$PATH` when built with the `"inline-asm"` feature disabled (which is disabled by default). + +- [breaking-change] The `register::{apsr,lr,pc}` modules are now behind the `"inline-asm"` feature. + +- [breaking-change] Some variants of the `Exception` enumeration are no longer available on + `thumbv6m-none-eabi`. See API docs for details. + +- [breaking-change] Several of the variants of the `Exception` enumeration have been renamed to + match the CMSIS specification. + +- [breaking-change] fixed typo in `shcrs` field of `scb::RegisterBlock`; it was previously named + `shpcrs`. + +- [breaking-change] removed several fields from `scb::RegisterBlock` on ARMv6-M. These registers are + not available on that sub-architecture. + +- [breaking-change] changed the type of `scb::RegisterBlock.shpr` from `RW` to `RW` on + ARMv6-M. These registers are word accessible only on that sub-architecture. + +- [breaking-change] renamed the `mmar` field of `scb::RegisterBlock` to `mmfar` to match the CMSIS + name. + +- [breaking-change] removed the `iabr` field from `scb::RegisterBlock` on ARMv6-M. This register is + not available on that sub-architecture. + +- [breaking-change] removed several fields from `cpuid::RegisterBlock` on ARMv6-M. These registers + are not available on that sub-architecture. + +- [breaking-change] The `Mutex.new` constructor is not a `const fn` by default. To make it a `const + fn` you have to opt into the `"const-fn"` feature, which was added in v0.5.1, and switch to a + nightly compiler. + +### Removed + +- [breaking-change] The `exception` module has been removed. A replacement for `Exception::active` + can be found in `SCB::vect_active`. A modified version `exception::Exception` can be found in the + `peripheral::scb` module. + +## [v0.4.3] - 2018-01-25 + +### Changed + +- The initial value of a `singleton!` no longer needs to be evaluable in const context; it can now + be a value computed at runtime, or even a capture of some other local variable. + +## [v0.4.2] - 2018-01-17 + +### Fixed + +- Added a missing `Send` implementation to all the peripherals. + +## [v0.4.1] - 2018-01-16 + +### Changed + +- `peripheral::Peripherals` is now re-exported at the root of the crate. + +## [v0.4.0] - 2018-01-15 + +### Added + +- Formatter and Flush Control register (FFCR) accessor to the TPIU register block. + +- A `singleton!` macro that creates mutable reference to a statically allocated variable. + +- A Cargo feature, `cm7-r0p1`, to work around a silicon erratum that affects writes to BASEPRI on + Cortex-M7 r0p1 devices. + +### Changed + +- [breaking-change] All peripherals are now exposed as scoped singletons and they need to be `take`n + into scope to become accessible. + +- [breaking-change] The signatures of methods exposed by peripheral proxies have changed to + better match the new scoped singletons semantics. + +- All the thin wrappers around assembly instructions now panic when executed on non-ARM devices. + +### Removed + +- [breaking-change] APIs specific to ARMv7-M (`peripheral::{cbp, fpb, fpu, itm, tpiu}`, `itm`) when + compiling for `thumb6m-none-eabi`. + +## [v0.3.1] - 2017-07-20 + +### Changed + +- `{basepri,basepri_max}::write` are now compiler barriers for the same reason + that `interrupt::{disable,enable}` are: they are used to create critical + sections. + +## [v0.3.0] - 2017-07-07 + +### Changed + +- [breaking-change] Renamed `StackedRergisters` to `ExceptionFrame` to better + reflect the ARM documentation. + +- [breaking-change] Renamed the variants of `Exception` to better match the + ARM documentation. + +- [breaking-change] Renamed `Exception::current` to `Exception::active` and + changed the signature to return `None` when no exception is being serviced. + +- Moved bits non specific to the Cortex-M architecture into the [`bare-metal`] + crate with the goal of sharing code between this crate and crates tailored for + other (microcontroller) architectures. + +[`bare-metal`]: https://crates.io/crates/bare-metal + +### Removed + +- [breaking-change] The `ctxt` module along with the exception "tokens" in the + `exception` module. The `cortex-m-rt` crate v0.3.0 provides a more ergonomic + mechanism to add state to interrupts / exceptions; replace your uses of + `Local` with that. + +- [breaking-change] `default_handler`, `DEFAULT_HANDLERS` and `Handlers` from + the `exception` module as well as `Reserved` from the root of the crate. + `cortex-m-rt` v0.3.0 provides a mechanism to override exceptions and the + default exception handler. Change your use of these `Handlers` and others to + that. + +### Fixed + +- `interrupt::{enable,disable}` are now compiler barriers. The compiler should + not reorder code around these function calls for memory safety; that is the + case now. + +## [v0.2.11] - 2017-06-16 + +### Added + +- An API to maintain the different caches (DCache, ICache) on Cortex M7 devices. + +### Fixed + +- the definition of the `ehprint!` macro. +- the implementation of the FPU API. + +## [v0.2.10] - 2017-06-05 + +### Added + +- Functions for the instructions DMB, ISB and DSB + +### Changed + +- All the functions in the `asm` module are now `inline(always)` + +## [v0.2.9] - 2017-05-30 + +### Fixed + +- A bug in `itm::write_all` where it would ignore the length of the buffer and + serialize contents that come after the buffer. + +## [v0.2.8] - 2017-05-30 - YANKED + +### Added + +- An `itm::write_aligned` function to write 4 byte aligned buffers to an ITM + port. This function is faster than `itm::write_all` for small buffers but + requires the buffer to be aligned. + +## [v0.2.7] - 2017-05-23 + +### Added + +- `Dwt.enable_cycle_counter` + +## [v0.2.6] - 2017-05-08 + +### Fixed + +- [breaking-change]. MEMORY UNSAFETY. `Mutex` could be used as a channel to send + interrupt tokens from one interrupt to other thus breaking the context `Local` + abstraction. See reproduction case below. This has been fixed by making + `Mutex` `Sync` only if the protected data is `Send`. + +``` rust +#![feature(const_fn)] +#![feature(used)] +#![no_std] + +use core::cell::RefCell; + +use cortex_m::ctxt::Local; +use cortex_m::interrupt::Mutex; +use stm32f30x::interrupt::{self, Exti0, Exti1}; + +fn main() { + // .. + + // trigger exti0 + // then trigger exti0 again +} + +static CHANNEL: Mutex>> = Mutex::new(RefCell::new(None)); +// Supposedly task *local* data +static LOCAL: Local = Local::new(0); + +extern "C" fn exti0(mut ctxt: Exti0) { + static FIRST: Local = Local::new(true); + + let first = *FIRST.borrow(&ctxt); + + // toggle + if first { + *FIRST.borrow_mut(&mut ctxt) = false; + } + + if first { + cortex_m::interrupt::free( + |cs| { + let channel = CHANNEL.borrow(cs); + + // BAD: transfer interrupt token to another interrupt + *channel.borrow_mut() = Some(ctxt); + }, + ); + + return; + } + let _local = LOCAL.borrow_mut(&mut ctxt); + + // .. + + // trigger exti1 here + + // .. + + // `LOCAL` mutably borrowed up to this point +} + +extern "C" fn exti1(_ctxt: Exti1) { + cortex_m::interrupt::free(|cs| { + let channel = CHANNEL.borrow(cs); + let mut channel = channel.borrow_mut(); + + if let Some(mut other_task) = channel.take() { + // BAD: `exti1` has access to `exti0`'s interrupt token + // so it can now mutably access local while `exti0` is also using it + let _local = LOCAL.borrow_mut(&mut other_task); + } + }); +} + +#[allow(dead_code)] +#[used] +#[link_section = ".rodata.interrupts"] +static INTERRUPTS: interrupt::Handlers = interrupt::Handlers { + Exti0: exti0, + Exti1: exti1, + ..interrupt::DEFAULT_HANDLERS +}; +``` + +## [v0.2.5] - 2017-05-07 - YANKED + +### Added + +- Higher level API for the SysTick and FPU peripherals + +### Fixed + +- [breaking-change]. MEMORY UNSAFETY. `interrupt::enable` was safe to call + inside an `interrupt::free` critical section thus breaking the preemption + protection. The `interrupt::enable` method is now `unsafe`. + +## [v0.2.4] - 2017-04-20 - YANKED + +### Fixed + +- [breaking-change]. MEMORY UNSAFETY. `interrupt::free` leaked the critical + section making it possible to access a `Mutex` when interrupts are enabled + (see below). This has been fixed by changing the signature of + `interrupt::free`. + +``` rust +static FOO: Mutex = Mutex::new(false); + +fn main() { + let cs = cortex_m::interrupt::free(|cs| cs); + // interrupts are enabled at this point + let foo = FOO.borrow(&cs); +} +``` + +## [v0.2.3] - 2017-04-11 - YANKED + +### Fixed + +- [breaking-change]. MEMORY UNSAFETY. Some concurrency models that use "partial" + critical sections (cf. BASEPRI) can be broken by changing the priority of + interrupts or by changing BASEPRI in some scenarios. For this reason + `NVIC.set_priority` and `register::basepri::write` are now `unsafe`. + +## [v0.2.2] - 2017-04-08 - YANKED + +### Fixed + +- [breaking-change]. MEMORY UNSAFETY. The `Mutex.borrow_mut` method has been + removed as it can be used to bypass Rust's borrow checker and get, for + example, two mutable references to the same data. + +``` rust +static FOO: Mutex = Mutex::new(false); + +fn main() { + cortex_m::interrupt::free(|mut cs1| { + cortex_m::interrupt::free(|mut cs2| { + let foo: &mut bool = FOO.borrow_mut(&mut cs1); + let and_foo: &mut bool = FOO.borrow_mut(&mut cs2); + }); + }); +} +``` + +## [v0.2.1] - 2017-03-12 - YANKED + +### Changed + +- The default exception handler now identifies the exception that's being + serviced. + +## [v0.2.0] - 2017-03-11 - YANKED + +### Added + +- Semihosting functionality in the `semihosting` module. + +- `exception::Handlers` struct that represent the section of the vector table + that contains the exception handlers. + +- A default exception handler + +- A high level API for the NVIC peripheral. + +- Context local data. + +- `borrow`/`borrow_mut` methods to `Mutex` that replace `lock`. + +- API and macros to send bytes / (formatted) strings through ITM + +### Changed + +- [breaking-change] `StackFrame` has been renamed to `StackedRegisters` and + moved into the `exceptions` module. + +- [breaking-change] Core peripherals can now be modified via a `&-` reference + and are no longer `Sync`. + +- [breaking-change] `interrupt::free`'s closure now includes a critical section + token, `CriticalSection`. + +- [breaking-change] the core register API has been revamped for type safety. + +- The safety of assembly wrappers like `wfi` and `interrupt::free` has been + reviewed. In many cases, the functions are no longer unsafe. + +- [breaking-change] `bkpt!` has been turned into a function. It no longer + accepts an immediate value. + +### Removed + +- `vector_table` and its associated `struct`, `VectorTable`. It's not a good + idea to give people a simple way to call the exception handlers. + +- `Mutex`'s `lock` method as it's unsound. You could use it to get multiple + `&mut -` references to the wrapped data. + +## [v0.1.6] - 2017-01-22 + +### Added + +- `Exception` a enumeration of the kind of exceptions the processor can service. + There's also a `Exception::current` constructor that returns the `Exception` + that's currently being serviced. + +## [v0.1.5] + +### Added + +- `interrupt::Mutex`, a "mutex" based on critical sections. + +### Changed + +- The closure that `interrupt::free` takes can now return a value. + +## [v0.1.4] + +### Added + +- `asm::nop`, a wrapper over the NOP instruction + +## [v0.1.3] + +### Added + +- a StackFrame data structure + +## [v0.1.2] - 2016-10-04 + +### Fixed + +- Read/write Operations on registers (lr, cr, msp, etc.) which were reversed. + +## [v0.1.1] - 2016-10-03 - YANKED + +### Changed + +- Small, non user visible change to make this crate compile further for $HOST (e.g. x86_64) with the + goal of making it possible to test, on the HOST, downstream crates that depend on this one. + +## v0.1.0 - 2016-09-27 - YANKED + +### Added + +- Functions to access core peripherals like NVIC, SCB and SysTick. +- Functions to access core registers like CONTROL, MSP and PSR. +- Functions to enable/disable interrupts +- Functions to get the vector table +- Wrappers over miscellaneous instructions like `bkpt` + +[Unreleased]: https://github.com/rust-embedded/cortex-m/compare/v0.7.7...HEAD +[v0.7.7]: https://github.com/rust-embedded/cortex-m/compare/v0.7.6...v0.7.7 +[v0.7.6]: https://github.com/rust-embedded/cortex-m/compare/v0.7.5...v0.7.6 +[v0.7.5]: https://github.com/rust-embedded/cortex-m/compare/v0.7.4...v0.7.5 +[v0.7.4]: https://github.com/rust-embedded/cortex-m/compare/v0.7.3...v0.7.4 +[v0.7.3]: https://github.com/rust-embedded/cortex-m/compare/v0.7.2...v0.7.3 +[v0.7.2]: https://github.com/rust-embedded/cortex-m/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/rust-embedded/cortex-m/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/rust-embedded/cortex-m/compare/v0.6.4...v0.7.0 +[v0.6.7]: https://github.com/rust-embedded/cortex-m/compare/v0.6.6...v0.6.7 +[v0.6.6]: https://github.com/rust-embedded/cortex-m/compare/v0.6.5...v0.6.6 +[v0.6.5]: https://github.com/rust-embedded/cortex-m/compare/v0.6.4...v0.6.5 +[v0.6.4]: https://github.com/rust-embedded/cortex-m/compare/v0.6.3...v0.6.4 +[v0.6.3]: https://github.com/rust-embedded/cortex-m/compare/v0.6.2...v0.6.3 +[v0.6.2]: https://github.com/rust-embedded/cortex-m/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/rust-embedded/cortex-m/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/rust-embedded/cortex-m/compare/v0.5.8...v0.6.0 +[v0.5.8]: https://github.com/rust-embedded/cortex-m/compare/v0.5.7...v0.5.8 +[v0.5.7]: https://github.com/rust-embedded/cortex-m/compare/v0.5.6...v0.5.7 +[v0.5.6]: https://github.com/rust-embedded/cortex-m/compare/v0.5.5...v0.5.6 +[v0.5.5]: https://github.com/rust-embedded/cortex-m/compare/v0.5.4...v0.5.5 +[v0.5.4]: https://github.com/rust-embedded/cortex-m/compare/v0.5.3...v0.5.4 +[v0.5.3]: https://github.com/rust-embedded/cortex-m/compare/v0.5.2...v0.5.3 +[v0.5.2]: https://github.com/rust-embedded/cortex-m/compare/v0.5.1...v0.5.2 +[v0.5.1]: https://github.com/rust-embedded/cortex-m/compare/v0.5.0...v0.5.1 +[v0.5.0]: https://github.com/rust-embedded/cortex-m/compare/v0.4.3...v0.5.0 +[v0.4.3]: https://github.com/rust-embedded/cortex-m/compare/v0.4.2...v0.4.3 +[v0.4.2]: https://github.com/rust-embedded/cortex-m/compare/v0.4.1...v0.4.2 +[v0.4.1]: https://github.com/rust-embedded/cortex-m/compare/v0.4.0...v0.4.1 +[v0.4.0]: https://github.com/rust-embedded/cortex-m/compare/v0.3.1...v0.4.0 +[v0.3.1]: https://github.com/rust-embedded/cortex-m/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/rust-embedded/cortex-m/compare/v0.2.11...v0.3.0 +[v0.2.11]: https://github.com/rust-embedded/cortex-m/compare/v0.2.10...v0.2.11 +[v0.2.10]: https://github.com/rust-embedded/cortex-m/compare/v0.2.9...v0.2.10 +[v0.2.9]: https://github.com/rust-embedded/cortex-m/compare/v0.2.8...v0.2.9 +[v0.2.8]: https://github.com/rust-embedded/cortex-m/compare/v0.2.7...v0.2.8 +[v0.2.7]: https://github.com/rust-embedded/cortex-m/compare/v0.2.6...v0.2.7 +[v0.2.6]: https://github.com/rust-embedded/cortex-m/compare/v0.2.5...v0.2.6 +[v0.2.5]: https://github.com/rust-embedded/cortex-m/compare/v0.2.4...v0.2.5 +[v0.2.4]: https://github.com/rust-embedded/cortex-m/compare/v0.2.3...v0.2.4 +[v0.2.3]: https://github.com/rust-embedded/cortex-m/compare/v0.2.2...v0.2.3 +[v0.2.2]: https://github.com/rust-embedded/cortex-m/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-embedded/cortex-m/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-embedded/cortex-m/compare/v0.1.6...v0.2.0 +[v0.1.6]: https://github.com/rust-embedded/cortex-m/compare/v0.1.5...v0.1.6 +[v0.1.5]: https://github.com/rust-embedded/cortex-m/compare/v0.1.4...v0.1.5 +[v0.1.4]: https://github.com/rust-embedded/cortex-m/compare/v0.1.3...v0.1.4 +[v0.1.3]: https://github.com/rust-embedded/cortex-m/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/rust-embedded/cortex-m/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-embedded/cortex-m/compare/v0.1.0...v0.1.1 diff --git a/src/rust/vendor/cortex-m/CODE_OF_CONDUCT.md b/src/rust/vendor/cortex-m/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..3ab76c639 --- /dev/null +++ b/src/rust/vendor/cortex-m/CODE_OF_CONDUCT.md @@ -0,0 +1,37 @@ +# The Rust Code of Conduct + +## Conduct + +**Contact**: [Cortex-M team](https://github.com/rust-embedded/wg#the-cortex-m-team) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Cortex-M team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[team]: https://github.com/rust-embedded/wg#the-cortex-m-team diff --git a/src/rust/vendor/cortex-m/Cargo.toml b/src/rust/vendor/cortex-m/Cargo.toml new file mode 100644 index 000000000..a86829c68 --- /dev/null +++ b/src/rust/vendor/cortex-m/Cargo.toml @@ -0,0 +1,77 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "cortex-m" +version = "0.7.7" +authors = [ + "The Cortex-M Team ", + "Jorge Aparicio ", +] +links = "cortex-m" +description = "Low level access to Cortex-M processors" +documentation = "https://docs.rs/cortex-m" +readme = "README.md" +keywords = [ + "arm", + "cortex-m", + "register", + "peripheral", +] +categories = [ + "embedded", + "hardware-support", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-embedded/cortex-m" + +[package.metadata.docs.rs] +targets = [ + "thumbv8m.main-none-eabihf", + "thumbv6m-none-eabi", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", +] + +[dependencies.bare-metal] +version = "0.2.4" +features = ["const-fn"] + +[dependencies.bitfield] +version = "0.13.2" + +[dependencies.critical-section] +version = "1.0.0" +optional = true + +[dependencies.embedded-hal] +version = "0.2.4" + +[dependencies.serde] +version = "1" +features = ["derive"] +optional = true + +[dependencies.volatile-register] +version = "0.2.0" + +[features] +cm7 = [] +cm7-r0p1 = ["cm7"] +critical-section-single-core = ["critical-section/restore-state-bool"] +inline-asm = [] +linker-plugin-lto = [] +std = [] diff --git a/src/rust/vendor/cortex-m/LICENSE-APACHE b/src/rust/vendor/cortex-m/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/cortex-m/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/cortex-m/LICENSE-MIT b/src/rust/vendor/cortex-m/LICENSE-MIT new file mode 100644 index 000000000..a43445e6c --- /dev/null +++ b/src/rust/vendor/cortex-m/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/cortex-m/README.md b/src/rust/vendor/cortex-m/README.md new file mode 100644 index 000000000..6bd8aeddc --- /dev/null +++ b/src/rust/vendor/cortex-m/README.md @@ -0,0 +1,39 @@ +[![crates.io](https://img.shields.io/crates/d/cortex-m.svg)](https://crates.io/crates/cortex-m) +[![crates.io](https://img.shields.io/crates/v/cortex-m.svg)](https://crates.io/crates/cortex-m) + +# `cortex-m` + +> Low level access to Cortex-M processors + +This project is developed and maintained by the [Cortex-M team][team]. + +## [Documentation](https://docs.rs/crate/cortex-m) + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.38 and up. It might compile with older versions but that may change in any new patch release. + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the +work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [Cortex-M team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-cortex-m-team diff --git a/src/rust/vendor/cortex-m/asm-toolchain b/src/rust/vendor/cortex-m/asm-toolchain new file mode 100644 index 000000000..cc5dbb24a --- /dev/null +++ b/src/rust/vendor/cortex-m/asm-toolchain @@ -0,0 +1 @@ +nightly-2021-12-16 diff --git a/src/rust/vendor/cortex-m/asm/inline.rs b/src/rust/vendor/cortex-m/asm/inline.rs new file mode 100644 index 000000000..bbc04d2ba --- /dev/null +++ b/src/rust/vendor/cortex-m/asm/inline.rs @@ -0,0 +1,448 @@ +//! Inline assembly implementing the routines exposed in `cortex_m::asm`. +//! +//! If the `inline-asm` feature is enabled, these functions will be directly called by the +//! `cortex-m` wrappers. Otherwise, `cortex-m` links against them via prebuilt archives. +//! +//! All of these functions should be blanket-`unsafe`. `cortex-m` provides safe wrappers where +//! applicable. + +use core::arch::asm; +use core::sync::atomic::{compiler_fence, Ordering}; + +#[inline(always)] +pub unsafe fn __bkpt() { + asm!("bkpt", options(nomem, nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn __control_r() -> u32 { + let r; + asm!("mrs {}, CONTROL", out(reg) r, options(nomem, nostack, preserves_flags)); + r +} + +#[inline(always)] +pub unsafe fn __control_w(w: u32) { + // ISB is required after writing to CONTROL, + // per ARM architectural requirements (see Application Note 321). + asm!( + "msr CONTROL, {}", + "isb", + in(reg) w, + options(nomem, nostack, preserves_flags), + ); + + // Ensure memory accesses are not reordered around the CONTROL update. + compiler_fence(Ordering::SeqCst); +} + +#[inline(always)] +pub unsafe fn __cpsid() { + asm!("cpsid i", options(nomem, nostack, preserves_flags)); + + // Ensure no subsequent memory accesses are reordered to before interrupts are disabled. + compiler_fence(Ordering::SeqCst); +} + +#[inline(always)] +pub unsafe fn __cpsie() { + // Ensure no preceeding memory accesses are reordered to after interrupts are enabled. + compiler_fence(Ordering::SeqCst); + + asm!("cpsie i", options(nomem, nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn __delay(cyc: u32) { + // The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores + // (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying + // for more cycles is okay. + // Add 1 to prevent an integer underflow which would cause a long freeze + let real_cyc = 1 + cyc / 2; + asm!( + // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m. + "1:", + "subs {}, #1", + "bne 1b", + inout(reg) real_cyc => _, + options(nomem, nostack), + ); +} + +#[inline(always)] +pub unsafe fn __dmb() { + compiler_fence(Ordering::SeqCst); + asm!("dmb", options(nomem, nostack, preserves_flags)); + compiler_fence(Ordering::SeqCst); +} + +#[inline(always)] +pub unsafe fn __dsb() { + compiler_fence(Ordering::SeqCst); + asm!("dsb", options(nomem, nostack, preserves_flags)); + compiler_fence(Ordering::SeqCst); +} + +#[inline(always)] +pub unsafe fn __isb() { + compiler_fence(Ordering::SeqCst); + asm!("isb", options(nomem, nostack, preserves_flags)); + compiler_fence(Ordering::SeqCst); +} + +#[inline(always)] +pub unsafe fn __msp_r() -> u32 { + let r; + asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags)); + r +} + +#[inline(always)] +pub unsafe fn __msp_w(val: u32) { + // Technically is writing to the stack pointer "not pushing any data to the stack"? + // In any event, if we don't set `nostack` here, this method is useless as the new + // stack value is immediately mutated by returning. Really this is just not a good + // method and its higher-level use is marked as deprecated in cortex-m. + asm!("msr MSP, {}", in(reg) val, options(nomem, nostack, preserves_flags)); +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __apsr_r() -> u32 { + let r; + asm!("mrs {}, APSR", out(reg) r, options(nomem, nostack, preserves_flags)); + r +} + +#[inline(always)] +pub unsafe fn __nop() { + // NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate + // the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N + // nops when they call `nop` N times, let's not add that option. + asm!("nop", options(nomem, nostack, preserves_flags)); +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __pc_r() -> u32 { + let r; + asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags)); + r +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __pc_w(val: u32) { + asm!("mov pc, {}", in(reg) val, options(nomem, nostack, preserves_flags)); +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __lr_r() -> u32 { + let r; + asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags)); + r +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __lr_w(val: u32) { + asm!("mov lr, {}", in(reg) val, options(nomem, nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn __primask_r() -> u32 { + let r; + asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags)); + r +} + +#[inline(always)] +pub unsafe fn __psp_r() -> u32 { + let r; + asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags)); + r +} + +#[inline(always)] +pub unsafe fn __psp_w(val: u32) { + // See comment on __msp_w. Unlike MSP, there are legitimate use-cases for modifying PSP + // if MSP is currently being used as the stack pointer. + asm!("msr PSP, {}", in(reg) val, options(nomem, nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn __sev() { + asm!("sev", options(nomem, nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn __udf() -> ! { + asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn __wfe() { + asm!("wfe", options(nomem, nostack, preserves_flags)); +} + +#[inline(always)] +pub unsafe fn __wfi() { + asm!("wfi", options(nomem, nostack, preserves_flags)); +} + +/// Semihosting syscall. +#[inline(always)] +pub unsafe fn __sh_syscall(mut nr: u32, arg: u32) -> u32 { + asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags)); + nr +} + +/// Set CONTROL.SPSEL to 0, write `msp` to MSP, branch to `rv`. +#[inline(always)] +pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! { + asm!( + "mrs {tmp}, CONTROL", + "bics {tmp}, {spsel}", + "msr CONTROL, {tmp}", + "isb", + "msr MSP, {msp}", + "bx {rv}", + // `out(reg) _` is not permitted in a `noreturn` asm! call, + // so instead use `in(reg) 0` and don't restore it afterwards. + tmp = in(reg) 0, + spsel = in(reg) 2, + msp = in(reg) msp, + rv = in(reg) rv, + options(noreturn, nomem, nostack), + ); +} + +// v7m *AND* v8m.main, but *NOT* v8m.base +#[cfg(any(armv7m, armv8m_main))] +pub use self::v7m::*; +#[cfg(any(armv7m, armv8m_main))] +mod v7m { + use core::arch::asm; + use core::sync::atomic::{compiler_fence, Ordering}; + + #[inline(always)] + pub unsafe fn __basepri_max(val: u8) { + asm!("msr BASEPRI_MAX, {}", in(reg) val, options(nomem, nostack, preserves_flags)); + } + + #[inline(always)] + pub unsafe fn __basepri_r() -> u8 { + let r; + asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags)); + r + } + + #[inline(always)] + pub unsafe fn __basepri_w(val: u8) { + asm!("msr BASEPRI, {}", in(reg) val, options(nomem, nostack, preserves_flags)); + } + + #[inline(always)] + pub unsafe fn __faultmask_r() -> u32 { + let r; + asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags)); + r + } + + #[inline(always)] + pub unsafe fn __enable_icache() { + asm!( + "ldr {0}, =0xE000ED14", // CCR + "mrs {2}, PRIMASK", // save critical nesting info + "cpsid i", // mask interrupts + "ldr {1}, [{0}]", // read CCR + "orr.w {1}, {1}, #(1 << 17)", // Set bit 17, IC + "str {1}, [{0}]", // write it back + "dsb", // ensure store completes + "isb", // synchronize pipeline + "msr PRIMASK, {2}", // unnest critical section + out(reg) _, + out(reg) _, + out(reg) _, + options(nostack), + ); + compiler_fence(Ordering::SeqCst); + } + + #[inline(always)] + pub unsafe fn __enable_dcache() { + asm!( + "ldr {0}, =0xE000ED14", // CCR + "mrs {2}, PRIMASK", // save critical nesting info + "cpsid i", // mask interrupts + "ldr {1}, [{0}]", // read CCR + "orr.w {1}, {1}, #(1 << 16)", // Set bit 16, DC + "str {1}, [{0}]", // write it back + "dsb", // ensure store completes + "isb", // synchronize pipeline + "msr PRIMASK, {2}", // unnest critical section + out(reg) _, + out(reg) _, + out(reg) _, + options(nostack), + ); + compiler_fence(Ordering::SeqCst); + } +} + +#[cfg(armv7em)] +pub use self::v7em::*; +#[cfg(armv7em)] +mod v7em { + use core::arch::asm; + + #[inline(always)] + pub unsafe fn __basepri_max_cm7_r0p1(val: u8) { + asm!( + "mrs {1}, PRIMASK", + "cpsid i", + "tst.w {1}, #1", + "msr BASEPRI_MAX, {0}", + "it ne", + "bxne lr", + "cpsie i", + in(reg) val, + out(reg) _, + options(nomem, nostack, preserves_flags), + ); + } + + #[inline(always)] + pub unsafe fn __basepri_w_cm7_r0p1(val: u8) { + asm!( + "mrs {1}, PRIMASK", + "cpsid i", + "tst.w {1}, #1", + "msr BASEPRI, {0}", + "it ne", + "bxne lr", + "cpsie i", + in(reg) val, + out(reg) _, + options(nomem, nostack, preserves_flags), + ); + } +} + +#[cfg(armv8m)] +pub use self::v8m::*; +/// Baseline and Mainline. +#[cfg(armv8m)] +mod v8m { + use core::arch::asm; + + #[inline(always)] + pub unsafe fn __tt(mut target: u32) -> u32 { + asm!( + "tt {target}, {target}", + target = inout(reg) target, + options(nomem, nostack, preserves_flags), + ); + target + } + + #[inline(always)] + pub unsafe fn __ttt(mut target: u32) -> u32 { + asm!( + "ttt {target}, {target}", + target = inout(reg) target, + options(nomem, nostack, preserves_flags), + ); + target + } + + #[inline(always)] + pub unsafe fn __tta(mut target: u32) -> u32 { + asm!( + "tta {target}, {target}", + target = inout(reg) target, + options(nomem, nostack, preserves_flags), + ); + target + } + + #[inline(always)] + pub unsafe fn __ttat(mut target: u32) -> u32 { + asm!( + "ttat {target}, {target}", + target = inout(reg) target, + options(nomem, nostack, preserves_flags), + ); + target + } + + #[inline(always)] + pub unsafe fn __msp_ns_r() -> u32 { + let r; + asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags)); + r + } + + #[inline(always)] + pub unsafe fn __msp_ns_w(val: u32) { + asm!("msr MSP_NS, {}", in(reg) val, options(nomem, nostack, preserves_flags)); + } + + #[inline(always)] + pub unsafe fn __bxns(val: u32) { + asm!("BXNS {}", in(reg) val, options(nomem, nostack, preserves_flags)); + } +} + +#[cfg(armv8m_main)] +pub use self::v8m_main::*; +/// Mainline only. +#[cfg(armv8m_main)] +mod v8m_main { + use core::arch::asm; + + #[inline(always)] + pub unsafe fn __msplim_r() -> u32 { + let r; + asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)); + r + } + + #[inline(always)] + pub unsafe fn __msplim_w(val: u32) { + asm!("msr MSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags)); + } + + #[inline(always)] + pub unsafe fn __psplim_r() -> u32 { + let r; + asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)); + r + } + + #[inline(always)] + pub unsafe fn __psplim_w(val: u32) { + asm!("msr PSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags)); + } +} + +#[cfg(has_fpu)] +pub use self::fpu::*; +/// All targets with FPU. +#[cfg(has_fpu)] +mod fpu { + use core::arch::asm; + + #[inline(always)] + pub unsafe fn __fpscr_r() -> u32 { + let r; + asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags)); + r + } + + #[inline(always)] + pub unsafe fn __fpscr_w(val: u32) { + asm!("vmsr fpscr, {}", in(reg) val, options(nomem, nostack)); + } +} diff --git a/src/rust/vendor/cortex-m/asm/lib.rs b/src/rust/vendor/cortex-m/asm/lib.rs new file mode 100644 index 000000000..48f3dc211 --- /dev/null +++ b/src/rust/vendor/cortex-m/asm/lib.rs @@ -0,0 +1,143 @@ +//! FFI shim around the inline assembly in `inline.rs`. +//! +//! We use this file to precompile some assembly stubs into the static libraries you can find in +//! `bin`. Apps using the `cortex-m` crate then link against those static libraries and don't need +//! to build this file themselves. +//! +//! Nowadays the assembly stubs are no longer actual assembly files, but actually just this small +//! Rust crate that uses unstable inline assembly, coupled with the `xtask` tool to invoke rustc +//! and build the files. +//! +//! Precompiling this to a static lib allows users to call assembly routines from stable Rust, but +//! also perform [linker plugin LTO] with the precompiled artifacts to completely inline the +//! assembly routines into their code, which brings the "outline assembly" on par with "real" inline +//! assembly. +//! +//! For developers and contributors to `cortex-m`, this setup means that they don't have to install +//! any binutils, assembler, or C compiler to hack on the crate. All they need is to run `cargo +//! xtask assemble` to rebuild the archives from this file. +//! +//! Cool, right? +//! +//! # Rust version management +//! +//! Since inline assembly is still unstable, and we want to ensure that the created blobs are +//! up-to-date in CI, we have to pin the nightly version we use for this. The nightly toolchain is +//! stored in `asm-toolchain`. +//! +//! The `cargo xtask` automation will automatically install the `asm-toolchain` as well as all +//! Cortex-M targets needed to generate the blobs. +//! +//! [linker plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html + +#![feature(asm)] +#![no_std] +#![crate_type = "staticlib"] +#![deny(warnings)] +// Don't warn about feature(asm) being stable on Rust >= 1.59.0 +#![allow(stable_features)] + +mod inline; + +macro_rules! shims { + ( + $( fn $name:ident( $($arg:ident: $argty:ty),* ) $(-> $ret:ty)?; )+ + ) => { + $( + #[no_mangle] + pub unsafe extern "C" fn $name( + $($arg: $argty),* + ) $(-> $ret)? { + crate::inline::$name($($arg),*) + } + )+ + }; +} + +shims! { + fn __bkpt(); + fn __control_r() -> u32; + fn __control_w(w: u32); + fn __cpsid(); + fn __cpsie(); + fn __delay(cyc: u32); + fn __dmb(); + fn __dsb(); + fn __isb(); + fn __msp_r() -> u32; + fn __msp_w(val: u32); + fn __nop(); + fn __primask_r() -> u32; + fn __psp_r() -> u32; + fn __psp_w(val: u32); + fn __sev(); + fn __udf() -> !; + fn __wfe(); + fn __wfi(); + fn __sh_syscall(nr: u32, arg: u32) -> u32; + fn __bootstrap(msp: u32, rv: u32) -> !; +} + +// v7m *AND* v8m.main, but *NOT* v8m.base +#[cfg(any(armv7m, armv8m_main))] +shims! { + fn __basepri_max(val: u8); + fn __basepri_r() -> u8; + fn __basepri_w(val: u8); + fn __faultmask_r() -> u32; + fn __enable_icache(); + fn __enable_dcache(); +} + +#[cfg(armv7em)] +shims! { + fn __basepri_max_cm7_r0p1(val: u8); + fn __basepri_w_cm7_r0p1(val: u8); +} + +// Baseline and Mainline. +#[cfg(armv8m)] +shims! { + fn __tt(target: u32) -> u32; + fn __ttt(target: u32) -> u32; + fn __tta(target: u32) -> u32; + fn __ttat(target: u32) -> u32; + fn __msp_ns_r() -> u32; + fn __msp_ns_w(val: u32); + fn __bxns(val: u32); +} + +// Mainline only. +#[cfg(armv8m_main)] +shims! { + fn __msplim_r() -> u32; + fn __msplim_w(val: u32); + fn __psplim_r() -> u32; + fn __psplim_w(val: u32); +} + +// All targets with FPU. +#[cfg(has_fpu)] +shims! { + fn __fpscr_r() -> u32; + fn __fpscr_w(val: u32); +} + +/// We *must* define a panic handler here, even though nothing here should ever be able to panic. +/// +/// We prove that nothing will ever panic by calling a function that doesn't exist. If the panic +/// handler gets linked in, this causes a linker error. We always build this file with optimizations +/// enabled, but even without them the panic handler should never be linked in. +#[panic_handler] +#[link_section = ".text.asm_panic_handler"] +fn panic(_: &core::panic::PanicInfo) -> ! { + extern "C" { + #[link_name = "cortex-m internal error: panic handler not optimized out, please file an \ + issue at https://github.com/rust-embedded/cortex-m"] + fn __cortex_m_should_not_panic() -> !; + } + + unsafe { + __cortex_m_should_not_panic(); + } +} diff --git a/src/rust/vendor/cortex-m/bin/thumbv6m-none-eabi-lto.a b/src/rust/vendor/cortex-m/bin/thumbv6m-none-eabi-lto.a new file mode 100644 index 000000000..a203d7ae8 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv6m-none-eabi-lto.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv6m-none-eabi.a b/src/rust/vendor/cortex-m/bin/thumbv6m-none-eabi.a new file mode 100644 index 000000000..9640a6994 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv6m-none-eabi.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabi-lto.a b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabi-lto.a new file mode 100644 index 000000000..b34ac64f1 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabi-lto.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabi.a b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabi.a new file mode 100644 index 000000000..88acbddf6 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabi.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabihf-lto.a b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabihf-lto.a new file mode 100644 index 000000000..6de94bbf2 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabihf-lto.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabihf.a b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabihf.a new file mode 100644 index 000000000..cf91a7a59 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv7em-none-eabihf.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv7m-none-eabi-lto.a b/src/rust/vendor/cortex-m/bin/thumbv7m-none-eabi-lto.a new file mode 100644 index 000000000..7f677a931 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv7m-none-eabi-lto.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv7m-none-eabi.a b/src/rust/vendor/cortex-m/bin/thumbv7m-none-eabi.a new file mode 100644 index 000000000..ff4bf211c Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv7m-none-eabi.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv8m.base-none-eabi-lto.a b/src/rust/vendor/cortex-m/bin/thumbv8m.base-none-eabi-lto.a new file mode 100644 index 000000000..f62acafd3 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv8m.base-none-eabi-lto.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv8m.base-none-eabi.a b/src/rust/vendor/cortex-m/bin/thumbv8m.base-none-eabi.a new file mode 100644 index 000000000..c0cc96c4a Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv8m.base-none-eabi.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabi-lto.a b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabi-lto.a new file mode 100644 index 000000000..1a5151522 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabi-lto.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabi.a b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabi.a new file mode 100644 index 000000000..d017a15b7 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabi.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabihf-lto.a b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabihf-lto.a new file mode 100644 index 000000000..fd3dc9283 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabihf-lto.a differ diff --git a/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabihf.a b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabihf.a new file mode 100644 index 000000000..223ff1df3 Binary files /dev/null and b/src/rust/vendor/cortex-m/bin/thumbv8m.main-none-eabihf.a differ diff --git a/src/rust/vendor/cortex-m/build.rs b/src/rust/vendor/cortex-m/build.rs new file mode 100644 index 000000000..23ceebad4 --- /dev/null +++ b/src/rust/vendor/cortex-m/build.rs @@ -0,0 +1,54 @@ +use std::path::PathBuf; +use std::{env, fs}; + +fn main() { + let target = env::var("TARGET").unwrap(); + let host_triple = env::var("HOST").unwrap(); + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let name = env::var("CARGO_PKG_NAME").unwrap(); + + if host_triple == target { + println!("cargo:rustc-cfg=native"); + } + + if target.starts_with("thumb") { + let suffix = if env::var_os("CARGO_FEATURE_LINKER_PLUGIN_LTO").is_some() { + "-lto" + } else { + "" + }; + + fs::copy( + format!("bin/{}{}.a", target, suffix), + out_dir.join(format!("lib{}.a", name)), + ) + .unwrap(); + + println!("cargo:rustc-link-lib=static={}", name); + println!("cargo:rustc-link-search={}", out_dir.display()); + } + + if target.starts_with("thumbv6m-") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv6m"); + } else if target.starts_with("thumbv7m-") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv7m"); + } else if target.starts_with("thumbv7em-") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv7m"); + println!("cargo:rustc-cfg=armv7em"); // (not currently used) + } else if target.starts_with("thumbv8m.base") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv8m"); + println!("cargo:rustc-cfg=armv8m_base"); + } else if target.starts_with("thumbv8m.main") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv8m"); + println!("cargo:rustc-cfg=armv8m_main"); + } + + if target.ends_with("-eabihf") { + println!("cargo:rustc-cfg=has_fpu"); + } +} diff --git a/src/rust/vendor/cortex-m/src/asm.rs b/src/rust/vendor/cortex-m/src/asm.rs new file mode 100644 index 000000000..4dc1ab07c --- /dev/null +++ b/src/rust/vendor/cortex-m/src/asm.rs @@ -0,0 +1,209 @@ +//! Miscellaneous assembly instructions + +// When inline assembly is enabled, pull in the assembly routines here. `call_asm!` will invoke +// these routines. +#[cfg(feature = "inline-asm")] +#[path = "../asm/inline.rs"] +pub(crate) mod inline; + +/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint". +/// +/// **NOTE** calling `bkpt` when the processor is not connected to a debugger will cause an +/// exception. +#[inline(always)] +pub fn bkpt() { + call_asm!(__bkpt()); +} + +/// Blocks the program for *at least* `cycles` CPU cycles. +/// +/// This is implemented in assembly so its execution time is independent of the optimization +/// level, however it is dependent on the specific architecture and core configuration. +/// +/// NOTE that the delay can take much longer if interrupts are serviced during its execution +/// and the execution time may vary with other factors. This delay is mainly useful for simple +/// timer-less initialization of peripherals if and only if accurate timing is not essential. In +/// any other case please use a more accurate method to produce a delay. +#[inline] +pub fn delay(cycles: u32) { + call_asm!(__delay(cycles: u32)); +} + +/// A no-operation. Useful to prevent delay loops from being optimized away. +#[inline] +pub fn nop() { + call_asm!(__nop()); +} + +/// Generate an Undefined Instruction exception. +/// +/// Can be used as a stable alternative to `core::intrinsics::abort`. +#[inline] +pub fn udf() -> ! { + call_asm!(__udf() -> !) +} + +/// Wait For Event +#[inline] +pub fn wfe() { + call_asm!(__wfe()) +} + +/// Wait For Interrupt +#[inline] +pub fn wfi() { + call_asm!(__wfi()) +} + +/// Send Event +#[inline] +pub fn sev() { + call_asm!(__sev()) +} + +/// Instruction Synchronization Barrier +/// +/// Flushes the pipeline in the processor, so that all instructions following the `ISB` are fetched +/// from cache or memory, after the instruction has been completed. +#[inline] +pub fn isb() { + call_asm!(__isb()) +} + +/// Data Synchronization Barrier +/// +/// Acts as a special kind of memory barrier. No instruction in program order after this instruction +/// can execute until this instruction completes. This instruction completes only when both: +/// +/// * any explicit memory access made before this instruction is complete +/// * all cache and branch predictor maintenance operations before this instruction complete +#[inline] +pub fn dsb() { + call_asm!(__dsb()) +} + +/// Data Memory Barrier +/// +/// Ensures that all explicit memory accesses that appear in program order before the `DMB` +/// instruction are observed before any explicit memory accesses that appear in program order +/// after the `DMB` instruction. +#[inline] +pub fn dmb() { + call_asm!(__dmb()) +} + +/// Test Target +/// +/// Queries the Security state and access permissions of a memory location. +/// Returns a Test Target Response Payload (cf section D1.2.215 of +/// Armv8-M Architecture Reference Manual). +#[inline] +#[cfg(armv8m)] +// The __tt function does not dereference the pointer received. +#[allow(clippy::not_unsafe_ptr_arg_deref)] +pub fn tt(addr: *mut u32) -> u32 { + let addr = addr as u32; + call_asm!(__tt(addr: u32) -> u32) +} + +/// Test Target Unprivileged +/// +/// Queries the Security state and access permissions of a memory location for an unprivileged +/// access to that location. +/// Returns a Test Target Response Payload (cf section D1.2.215 of +/// Armv8-M Architecture Reference Manual). +#[inline] +#[cfg(armv8m)] +// The __ttt function does not dereference the pointer received. +#[allow(clippy::not_unsafe_ptr_arg_deref)] +pub fn ttt(addr: *mut u32) -> u32 { + let addr = addr as u32; + call_asm!(__ttt(addr: u32) -> u32) +} + +/// Test Target Alternate Domain +/// +/// Queries the Security state and access permissions of a memory location for a Non-Secure access +/// to that location. This instruction is only valid when executing in Secure state and is +/// undefined if used from Non-Secure state. +/// Returns a Test Target Response Payload (cf section D1.2.215 of +/// Armv8-M Architecture Reference Manual). +#[inline] +#[cfg(armv8m)] +// The __tta function does not dereference the pointer received. +#[allow(clippy::not_unsafe_ptr_arg_deref)] +pub fn tta(addr: *mut u32) -> u32 { + let addr = addr as u32; + call_asm!(__tta(addr: u32) -> u32) +} + +/// Test Target Alternate Domain Unprivileged +/// +/// Queries the Security state and access permissions of a memory location for a Non-Secure and +/// unprivileged access to that location. This instruction is only valid when executing in Secure +/// state and is undefined if used from Non-Secure state. +/// Returns a Test Target Response Payload (cf section D1.2.215 of +/// Armv8-M Architecture Reference Manual). +#[inline] +#[cfg(armv8m)] +// The __ttat function does not dereference the pointer received. +#[allow(clippy::not_unsafe_ptr_arg_deref)] +pub fn ttat(addr: *mut u32) -> u32 { + let addr = addr as u32; + call_asm!(__ttat(addr: u32) -> u32) +} + +/// Branch and Exchange Non-secure +/// +/// See section C2.4.26 of Armv8-M Architecture Reference Manual for details. +/// Undefined if executed in Non-Secure state. +#[inline] +#[cfg(armv8m)] +pub unsafe fn bx_ns(addr: u32) { + call_asm!(__bxns(addr: u32)); +} + +/// Semihosting syscall. +/// +/// This method is used by cortex-m-semihosting to provide semihosting syscalls. +#[inline] +pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 { + call_asm!(__sh_syscall(nr: u32, arg: u32) -> u32) +} + +/// Bootstrap. +/// +/// Clears CONTROL.SPSEL (setting the main stack to be the active stack), +/// updates the main stack pointer to the address in `msp`, then jumps +/// to the address in `rv`. +/// +/// # Safety +/// +/// `msp` and `rv` must point to valid stack memory and executable code, +/// respectively. +#[inline] +pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! { + // Ensure thumb mode is set. + let rv = (rv as u32) | 1; + let msp = msp as u32; + call_asm!(__bootstrap(msp: u32, rv: u32) -> !); +} + +/// Bootload. +/// +/// Reads the initial stack pointer value and reset vector from +/// the provided vector table address, sets the active stack to +/// the main stack, sets the main stack pointer to the new initial +/// stack pointer, then jumps to the reset vector. +/// +/// # Safety +/// +/// The provided `vector_table` must point to a valid vector +/// table, with a valid stack pointer as the first word and +/// a valid reset vector as the second word. +#[inline] +pub unsafe fn bootload(vector_table: *const u32) -> ! { + let msp = core::ptr::read_volatile(vector_table); + let rv = core::ptr::read_volatile(vector_table.offset(1)); + bootstrap(msp as *const u32, rv as *const u32); +} diff --git a/src/rust/vendor/cortex-m/src/call_asm.rs b/src/rust/vendor/cortex-m/src/call_asm.rs new file mode 100644 index 000000000..295277f38 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/call_asm.rs @@ -0,0 +1,24 @@ +/// An internal macro to invoke an assembly routine. +/// +/// Depending on whether the unstable `inline-asm` feature is enabled, this will either call into +/// the inline assembly implementation directly, or through the FFI shim (see `asm/lib.rs`). +macro_rules! call_asm { + ( $func:ident ( $($args:ident: $tys:ty),* ) $(-> $ret:ty)? ) => {{ + #[allow(unused_unsafe)] + unsafe { + match () { + #[cfg(feature = "inline-asm")] + () => crate::asm::inline::$func($($args),*), + + #[cfg(not(feature = "inline-asm"))] + () => { + extern "C" { + fn $func($($args: $tys),*) $(-> $ret)?; + } + + $func($($args),*) + }, + } + } + }}; +} diff --git a/src/rust/vendor/cortex-m/src/cmse.rs b/src/rust/vendor/cortex-m/src/cmse.rs new file mode 100644 index 000000000..36d744754 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/cmse.rs @@ -0,0 +1,238 @@ +//! Cortex-M Security Extensions +//! +//! This module provides several helper functions to support Armv8-M and Armv8.1-M Security +//! Extensions. +//! Most of this implementation is directly inspired by the "Armv8-M Security Extensions: +//! Requirements on Development Tools" document available here: +//! https://developer.arm.com/docs/ecm0359818/latest +//! +//! Please note that the TT instructions support as described part 4 of the document linked above is +//! not part of CMSE but is still present in this module. The TT instructions return the +//! configuration of the Memory Protection Unit at an address. +//! +//! # Notes +//! +//! * Non-Secure Unprivileged code will always read zeroes from TestTarget and should not use it. +//! * Non-Secure Privileged code can check current (AccessType::Current) and Non-Secure Unprivileged +//! accesses (AccessType::Unprivileged). +//! * Secure Unprivileged code can check Non-Secure Unprivileged accesses (AccessType::NonSecure). +//! * Secure Privileged code can check all access types. +//! +//! # Example +//! +//! ``` +//! use cortex_m::cmse::{TestTarget, AccessType}; +//! +//! // suspect_address was given by Non-Secure to a Secure function to write at it. +//! // But is it allowed to? +//! let suspect_address_test = TestTarget::check(0xDEADBEEF as *mut u32, +//! AccessType::NonSecureUnprivileged); +//! if suspect_address_test.ns_read_and_writable() { +//! // Non-Secure can not read or write this address! +//! } +//! ``` + +use crate::asm::{tt, tta, ttat, ttt}; +use bitfield::bitfield; + +/// Memory access behaviour: determine which privilege execution mode is used and which Memory +/// Protection Unit (MPU) is used. +#[derive(PartialEq, Copy, Clone, Debug)] +pub enum AccessType { + /// Access using current privilege level and reading from current security state MPU. + /// Uses the TT instruction. + Current, + /// Unprivileged access reading from current security state MPU. Uses the TTT instruction. + Unprivileged, + /// Access using current privilege level reading from Non-Secure MPU. Uses the TTA instruction. + /// Undefined if used from Non-Secure state. + NonSecure, + /// Unprivilege access reading from Non-Secure MPU. Uses the TTAT instruction. + /// Undefined if used from Non-Secure state. + NonSecureUnprivileged, +} + +/// Abstraction of TT instructions and helper functions to determine the security and privilege +/// attribute of a target address, accessed in different ways. +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct TestTarget { + tt_resp: TtResp, + access_type: AccessType, +} + +bitfield! { + /// Test Target Response Payload + /// + /// Provides the response payload from a TT, TTA, TTT or TTAT instruction. + #[derive(PartialEq, Copy, Clone)] + struct TtResp(u32); + impl Debug; + mregion, _: 7, 0; + sregion, _: 15, 8; + mrvalid, _: 16; + srvalid, _: 17; + r, _: 18; + rw, _: 19; + nsr, _: 20; + nsrw, _: 21; + s, _: 22; + irvalid, _: 23; + iregion, _: 31, 24; +} + +impl TestTarget { + /// Creates a Test Target Response Payload by testing addr using access_type. + #[inline] + pub fn check(addr: *mut u32, access_type: AccessType) -> Self { + let tt_resp = match access_type { + AccessType::Current => TtResp(tt(addr)), + AccessType::Unprivileged => TtResp(ttt(addr)), + AccessType::NonSecure => TtResp(tta(addr)), + AccessType::NonSecureUnprivileged => TtResp(ttat(addr)), + }; + + TestTarget { + tt_resp, + access_type, + } + } + + /// Creates a Test Target Response Payload by testing the zone from addr to addr + size - 1 + /// using access_type. + /// Returns None if: + /// * the address zone overlaps SAU, IDAU or MPU region boundaries + /// * size is 0 + /// * addr + size - 1 overflows + #[inline] + pub fn check_range(addr: *mut u32, size: usize, access_type: AccessType) -> Option { + let begin: usize = addr as usize; + // Last address of the range (addr + size - 1). This also checks if size is 0. + let end: usize = begin.checked_add(size.checked_sub(1)?)?; + + // Regions are aligned at 32-byte boundaries. If the address range fits in one 32-byte + // address line, a single TT instruction suffices. This is the case when the following + // constraint holds. + let single_check: bool = (begin % 32).checked_add(size)? <= 32usize; + + let test_start = TestTarget::check(addr, access_type); + + if single_check { + Some(test_start) + } else { + let test_end = TestTarget::check(end as *mut u32, access_type); + // Check that the range does not cross SAU, IDAU or MPU region boundaries. + if test_start != test_end { + None + } else { + Some(test_start) + } + } + } + + /// Access type that was used for this test target. + #[inline] + pub fn access_type(self) -> AccessType { + self.access_type + } + + /// Get the raw u32 value returned by the TT instruction used. + #[inline] + pub fn as_u32(self) -> u32 { + self.tt_resp.0 + } + + /// Read accessibility of the target address. Only returns the MPU settings without checking + /// the Security state of the target. + /// For Unprivileged and NonSecureUnprivileged access types, returns the permissions for + /// unprivileged access, regardless of whether the current mode is privileged or unprivileged. + /// Returns false if the TT instruction was executed from an unprivileged mode + /// and the NonSecure access type was not specified. + /// Returns false if the address matches multiple MPU regions. + #[inline] + pub fn readable(self) -> bool { + self.tt_resp.r() + } + + /// Read and write accessibility of the target address. Only returns the MPU settings without + /// checking the Security state of the target. + /// For Unprivileged and NonSecureUnprivileged access types, returns the permissions for + /// unprivileged access, regardless of whether the current mode is privileged or unprivileged. + /// Returns false if the TT instruction was executed from an unprivileged mode + /// and the NonSecure access type was not specified. + /// Returns false if the address matches multiple MPU regions. + #[inline] + pub fn read_and_writable(self) -> bool { + self.tt_resp.rw() + } + + /// Indicate the MPU region number containing the target address. + /// Returns None if the value is not valid: + /// * the MPU is not implemented or MPU_CTRL.ENABLE is set to zero + /// * the register argument specified by the MREGION field does not match any enabled MPU regions + /// * the address matched multiple MPU regions + /// * the address specified by the SREGION field is exempt from the secure memory attribution + /// * the TT instruction was executed from an unprivileged mode and the A flag was not specified. + #[inline] + pub fn mpu_region(self) -> Option { + if self.tt_resp.srvalid() { + // Cast is safe as SREGION field is defined on 8 bits. + Some(self.tt_resp.sregion() as u8) + } else { + None + } + } + + /// Indicates the Security attribute of the target address. Independent of AccessType. + /// Always zero when the test target is done in the Non-Secure state. + #[inline] + pub fn secure(self) -> bool { + self.tt_resp.s() + } + + /// Non-Secure Read accessibility of the target address. + /// Same as readable() && !secure() + #[inline] + pub fn ns_readable(self) -> bool { + self.tt_resp.nsr() + } + + /// Non-Secure Read and Write accessibility of the target address. + /// Same as read_and_writable() && !secure() + #[inline] + pub fn ns_read_and_writable(self) -> bool { + self.tt_resp.nsrw() + } + + /// Indicate the IDAU region number containing the target address. Independent of AccessType. + /// Returns None if the value is not valid: + /// * the IDAU cannot provide a region number + /// * the address is exempt from security attribution + /// * the test target is done from Non-Secure state + #[inline] + pub fn idau_region(self) -> Option { + if self.tt_resp.irvalid() { + // Cast is safe as IREGION field is defined on 8 bits. + Some(self.tt_resp.iregion() as u8) + } else { + None + } + } + + /// Indicate the SAU region number containing the target address. Independent of AccessType. + /// Returns None if the value is not valid: + /// * SAU_CTRL.ENABLE is set to zero + /// * the register argument specified in the SREGION field does not match any enabled SAU regions + /// * the address specified matches multiple enabled SAU regions + /// * the address specified by the SREGION field is exempt from the secure memory attribution + /// * the TT instruction was executed from the Non-secure state or the Security Extension is not + /// implemented + #[inline] + pub fn sau_region(self) -> Option { + if self.tt_resp.srvalid() { + // Cast is safe as SREGION field is defined on 8 bits. + Some(self.tt_resp.sregion() as u8) + } else { + None + } + } +} diff --git a/src/rust/vendor/cortex-m/src/critical_section.rs b/src/rust/vendor/cortex-m/src/critical_section.rs new file mode 100644 index 000000000..d33e90ff6 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/critical_section.rs @@ -0,0 +1,25 @@ +#[cfg(all(cortex_m, feature = "critical-section-single-core"))] +mod single_core_critical_section { + use critical_section::{set_impl, Impl, RawRestoreState}; + + use crate::interrupt; + use crate::register::primask; + + struct SingleCoreCriticalSection; + set_impl!(SingleCoreCriticalSection); + + unsafe impl Impl for SingleCoreCriticalSection { + unsafe fn acquire() -> RawRestoreState { + let was_active = primask::read().is_active(); + interrupt::disable(); + was_active + } + + unsafe fn release(was_active: RawRestoreState) { + // Only re-enable interrupts if they were enabled before the critical section. + if was_active { + interrupt::enable() + } + } + } +} diff --git a/src/rust/vendor/cortex-m/src/delay.rs b/src/rust/vendor/cortex-m/src/delay.rs new file mode 100644 index 000000000..66a63bf67 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/delay.rs @@ -0,0 +1,136 @@ +//! A delay driver based on SysTick. + +use crate::peripheral::{syst::SystClkSource, SYST}; +use embedded_hal::blocking::delay::{DelayMs, DelayUs}; + +/// System timer (SysTick) as a delay provider. +pub struct Delay { + syst: SYST, + frequency: u32, +} + +impl Delay { + /// Configures the system timer (SysTick) as a delay provider. + /// + /// `ahb_frequency` is a frequency of the AHB bus in Hz. + #[inline] + pub fn new(syst: SYST, ahb_frequency: u32) -> Self { + Self::with_source(syst, ahb_frequency, SystClkSource::Core) + } + + /// Configures the system timer (SysTick) as a delay provider + /// with a clock source. + /// + /// `frequency` is the frequency of your `clock_source` in Hz. + #[inline] + pub fn with_source(mut syst: SYST, frequency: u32, clock_source: SystClkSource) -> Self { + syst.set_clock_source(clock_source); + + Delay { syst, frequency } + } + + /// Releases the system timer (SysTick) resource. + #[inline] + pub fn free(self) -> SYST { + self.syst + } + + /// Delay using the Cortex-M systick for a certain duration, in µs. + #[allow(clippy::missing_inline_in_public_items)] + pub fn delay_us(&mut self, us: u32) { + let ticks = (u64::from(us)) * (u64::from(self.frequency)) / 1_000_000; + + let full_cycles = ticks >> 24; + if full_cycles > 0 { + self.syst.set_reload(0xffffff); + self.syst.clear_current(); + self.syst.enable_counter(); + + for _ in 0..full_cycles { + while !self.syst.has_wrapped() {} + } + } + + let ticks = (ticks & 0xffffff) as u32; + if ticks > 1 { + self.syst.set_reload(ticks - 1); + self.syst.clear_current(); + self.syst.enable_counter(); + + while !self.syst.has_wrapped() {} + } + + self.syst.disable_counter(); + } + + /// Delay using the Cortex-M systick for a certain duration, in ms. + #[inline] + pub fn delay_ms(&mut self, mut ms: u32) { + // 4294967 is the highest u32 value which you can multiply by 1000 without overflow + while ms > 4294967 { + self.delay_us(4294967000u32); + ms -= 4294967; + } + self.delay_us(ms * 1_000); + } +} + +impl DelayMs for Delay { + #[inline] + fn delay_ms(&mut self, ms: u32) { + Delay::delay_ms(self, ms); + } +} + +// This is a workaround to allow `delay_ms(42)` construction without specifying a type. +impl DelayMs for Delay { + #[inline(always)] + fn delay_ms(&mut self, ms: i32) { + assert!(ms >= 0); + Delay::delay_ms(self, ms as u32); + } +} + +impl DelayMs for Delay { + #[inline(always)] + fn delay_ms(&mut self, ms: u16) { + Delay::delay_ms(self, u32::from(ms)); + } +} + +impl DelayMs for Delay { + #[inline(always)] + fn delay_ms(&mut self, ms: u8) { + Delay::delay_ms(self, u32::from(ms)); + } +} + +impl DelayUs for Delay { + #[inline] + fn delay_us(&mut self, us: u32) { + Delay::delay_us(self, us); + } +} + +// This is a workaround to allow `delay_us(42)` construction without specifying a type. +impl DelayUs for Delay { + #[inline(always)] + fn delay_us(&mut self, us: i32) { + assert!(us >= 0); + Delay::delay_us(self, us as u32); + } +} + +impl DelayUs for Delay { + #[inline(always)] + fn delay_us(&mut self, us: u16) { + Delay::delay_us(self, u32::from(us)) + } +} + +impl DelayUs for Delay { + #[inline(always)] + fn delay_us(&mut self, us: u8) { + Delay::delay_us(self, u32::from(us)) + } +} diff --git a/src/rust/vendor/cortex-m/src/interrupt.rs b/src/rust/vendor/cortex-m/src/interrupt.rs new file mode 100644 index 000000000..0fd1284b3 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/interrupt.rs @@ -0,0 +1,73 @@ +//! Interrupts + +pub use bare_metal::{CriticalSection, Mutex, Nr}; + +/// Trait for enums of external interrupt numbers. +/// +/// This trait should be implemented by a peripheral access crate (PAC) +/// on its enum of available external interrupts for a specific device. +/// Each variant must convert to a u16 of its interrupt number, +/// which is its exception number - 16. +/// +/// # Safety +/// +/// This trait must only be implemented on enums of device interrupts. Each +/// enum variant must represent a distinct value (no duplicates are permitted), +/// and must always return the same value (do not change at runtime). +/// +/// These requirements ensure safe nesting of critical sections. +pub unsafe trait InterruptNumber: Copy { + /// Return the interrupt number associated with this variant. + /// + /// See trait documentation for safety requirements. + fn number(self) -> u16; +} + +/// Implement InterruptNumber for the old bare_metal::Nr trait. +/// This implementation is for backwards compatibility only and will be removed in cortex-m 0.8. +unsafe impl InterruptNumber for T { + #[inline] + fn number(self) -> u16 { + self.nr() as u16 + } +} + +/// Disables all interrupts +#[inline] +pub fn disable() { + call_asm!(__cpsid()); +} + +/// Enables all the interrupts +/// +/// # Safety +/// +/// - Do not call this function inside an `interrupt::free` critical section +#[inline] +pub unsafe fn enable() { + call_asm!(__cpsie()); +} + +/// Execute closure `f` in an interrupt-free context. +/// +/// This as also known as a "critical section". +#[inline] +pub fn free(f: F) -> R +where + F: FnOnce(&CriticalSection) -> R, +{ + let primask = crate::register::primask::read(); + + // disable interrupts + disable(); + + let r = f(unsafe { &CriticalSection::new() }); + + // If the interrupts were active before our `disable` call, then re-enable + // them. Otherwise, keep them disabled + if primask.is_active() { + unsafe { enable() } + } + + r +} diff --git a/src/rust/vendor/cortex-m/src/itm.rs b/src/rust/vendor/cortex-m/src/itm.rs new file mode 100644 index 000000000..72cb0d9a8 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/itm.rs @@ -0,0 +1,158 @@ +//! Instrumentation Trace Macrocell +//! +//! **NOTE** This module is only available on ARMv7-M and newer. + +use core::{fmt, ptr, slice}; + +use crate::peripheral::itm::Stim; + +// NOTE assumes that `bytes` is 32-bit aligned +unsafe fn write_words(stim: &mut Stim, bytes: &[u32]) { + let mut p = bytes.as_ptr(); + for _ in 0..bytes.len() { + while !stim.is_fifo_ready() {} + stim.write_u32(ptr::read(p)); + p = p.offset(1); + } +} + +/// Writes an aligned byte slice to the ITM. +/// +/// `buffer` must be 4-byte aligned. +unsafe fn write_aligned_impl(port: &mut Stim, buffer: &[u8]) { + let len = buffer.len(); + + if len == 0 { + return; + } + + let split = len & !0b11; + #[allow(clippy::cast_ptr_alignment)] + write_words( + port, + slice::from_raw_parts(buffer.as_ptr() as *const u32, split >> 2), + ); + + // 3 bytes or less left + let mut left = len & 0b11; + let mut ptr = buffer.as_ptr().add(split); + + // at least 2 bytes left + if left > 1 { + while !port.is_fifo_ready() {} + + #[allow(clippy::cast_ptr_alignment)] + port.write_u16(ptr::read(ptr as *const u16)); + + ptr = ptr.offset(2); + left -= 2; + } + + // final byte + if left == 1 { + while !port.is_fifo_ready() {} + port.write_u8(*ptr); + } +} + +struct Port<'p>(&'p mut Stim); + +impl<'p> fmt::Write for Port<'p> { + #[inline] + fn write_str(&mut self, s: &str) -> fmt::Result { + write_all(self.0, s.as_bytes()); + Ok(()) + } +} + +/// A wrapper type that aligns its contents on a 4-Byte boundary. +/// +/// ITM transfers are most efficient when the data is 4-Byte-aligned. This type provides an easy +/// way to accomplish and enforce such an alignment. +#[repr(align(4))] +pub struct Aligned(pub T); + +/// Writes `buffer` to an ITM port. +#[allow(clippy::missing_inline_in_public_items)] +pub fn write_all(port: &mut Stim, buffer: &[u8]) { + unsafe { + let mut len = buffer.len(); + let mut ptr = buffer.as_ptr(); + + if len == 0 { + return; + } + + // 0x01 OR 0x03 + if ptr as usize % 2 == 1 { + while !port.is_fifo_ready() {} + port.write_u8(*ptr); + + // 0x02 OR 0x04 + ptr = ptr.offset(1); + len -= 1; + } + + // 0x02 + if ptr as usize % 4 == 2 { + if len > 1 { + // at least 2 bytes + while !port.is_fifo_ready() {} + + // We checked the alignment above, so this is safe + #[allow(clippy::cast_ptr_alignment)] + port.write_u16(ptr::read(ptr as *const u16)); + + // 0x04 + ptr = ptr.offset(2); + len -= 2; + } else { + if len == 1 { + // last byte + while !port.is_fifo_ready() {} + port.write_u8(*ptr); + } + + return; + } + } + + // The remaining data is 4-byte aligned, but might not be a multiple of 4 bytes + write_aligned_impl(port, slice::from_raw_parts(ptr, len)); + } +} + +/// Writes a 4-byte aligned `buffer` to an ITM port. +/// +/// # Examples +/// +/// ```no_run +/// # use cortex_m::{itm::{self, Aligned}, peripheral::ITM}; +/// # let port = unsafe { &mut (*ITM::PTR).stim[0] }; +/// let mut buffer = Aligned([0; 14]); +/// +/// buffer.0.copy_from_slice(b"Hello, world!\n"); +/// +/// itm::write_aligned(port, &buffer); +/// +/// // Or equivalently +/// itm::write_aligned(port, &Aligned(*b"Hello, world!\n")); +/// ``` +#[allow(clippy::missing_inline_in_public_items)] +pub fn write_aligned(port: &mut Stim, buffer: &Aligned<[u8]>) { + unsafe { write_aligned_impl(port, &buffer.0) } +} + +/// Writes `fmt::Arguments` to the ITM `port` +#[inline] +pub fn write_fmt(port: &mut Stim, args: fmt::Arguments) { + use core::fmt::Write; + + Port(port).write_fmt(args).ok(); +} + +/// Writes a string to the ITM `port` +#[inline] +pub fn write_str(port: &mut Stim, string: &str) { + write_all(port, string.as_bytes()) +} diff --git a/src/rust/vendor/cortex-m/src/lib.rs b/src/rust/vendor/cortex-m/src/lib.rs new file mode 100644 index 000000000..044085ed0 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/lib.rs @@ -0,0 +1,112 @@ +//! Low level access to Cortex-M processors +//! +//! This crate provides: +//! +//! - Access to core peripherals like NVIC, SCB and SysTick. +//! - Access to core registers like CONTROL, MSP and PSR. +//! - Interrupt manipulation mechanisms +//! - Safe wrappers around Cortex-M specific instructions like `bkpt` +//! +//! # Optional features +//! +//! ## `inline-asm` +//! +//! When this feature is enabled the implementation of all the functions inside the `asm` and +//! `register` modules use inline assembly (`asm!`) instead of external assembly (FFI into separate +//! assembly files pre-compiled using `arm-none-eabi-gcc`). The advantages of enabling `inline-asm` +//! are: +//! +//! - Reduced overhead. FFI eliminates the possibility of inlining so all operations include a +//! function call overhead when `inline-asm` is not enabled. +//! +//! - Some of the `register` API only becomes available only when `inline-asm` is enabled. Check the +//! API docs for details. +//! +//! The disadvantage is that `inline-asm` requires a Rust version at least 1.59 to use the `asm!()` +//! macro. In the future 0.8 and above versions of `cortex-m`, this feature will always be enabled. +//! +//! ## `critical-section-single-core` +//! +//! This feature enables a [`critical-section`](https://github.com/rust-embedded/critical-section) +//! implementation suitable for single-core targets, based on disabling interrupts globally. +//! +//! It is **unsound** to enable it on multi-core targets or for code running in unprivileged mode, +//! and may cause functional problems in systems where some interrupts must be not be disabled +//! or critical sections are managed as part of an RTOS. In these cases, you should use +//! a target-specific implementation instead, typically provided by a HAL or RTOS crate. +//! +//! ## `cm7-r0p1` +//! +//! This feature enables workarounds for errata found on Cortex-M7 chips with revision r0p1. Some +//! functions in this crate only work correctly on those chips if this Cargo feature is enabled +//! (the functions are documented accordingly). +//! +//! ## `linker-plugin-lto` +//! +//! This feature links against prebuilt assembly blobs that are compatible with [Linker-Plugin LTO]. +//! This allows inlining assembly routines into the caller, even without the `inline-asm` feature, +//! and works on stable Rust (but note the drawbacks below!). +//! +//! If you want to use this feature, you need to be aware of a few things: +//! +//! - You need to make sure that `-Clinker-plugin-lto` is passed to rustc. Please refer to the +//! [Linker-Plugin LTO] documentation for details. +//! +//! - You have to use a Rust version whose LLVM version is compatible with the toolchain in +//! `asm-toolchain`. +//! +//! - Due to a [Rust bug][rust-lang/rust#75940] in compiler versions **before 1.49**, this option +//! does not work with optimization levels `s` and `z`. +//! +//! [Linker-Plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html +//! [rust-lang/rust#75940]: https://github.com/rust-lang/rust/issues/75940 +//! +//! # Minimum Supported Rust Version (MSRV) +//! +//! This crate is guaranteed to compile on stable Rust 1.38 and up. It *might* +//! compile with older versions but that may change in any new patch release. + +#![deny(missing_docs)] +#![no_std] +#![allow(clippy::identity_op)] +#![allow(clippy::missing_safety_doc)] +// Prevent clippy from complaining about empty match expression that are used for cfg gating. +#![allow(clippy::match_single_binding)] +// This makes clippy warn about public functions which are not #[inline]. +// +// Almost all functions in this crate result in trivial or even no assembly. +// These functions should be #[inline]. +// +// If you do add a function that's not supposed to be #[inline], you can add +// #[allow(clippy::missing_inline_in_public_items)] in front of it to add an +// exception to clippy's rules. +// +// This should be done in case of: +// - A function containing non-trivial logic (such as itm::write_all); or +// - A generated #[derive(Debug)] function (in which case the attribute needs +// to be applied to the struct). +#![deny(clippy::missing_inline_in_public_items)] +// Don't warn about feature(asm) being stable on Rust >= 1.59.0 +#![allow(stable_features)] + +extern crate bare_metal; +extern crate volatile_register; + +#[macro_use] +mod call_asm; +#[macro_use] +mod macros; + +pub mod asm; +#[cfg(armv8m)] +pub mod cmse; +mod critical_section; +pub mod delay; +pub mod interrupt; +#[cfg(all(not(armv6m), not(armv8m_base)))] +pub mod itm; +pub mod peripheral; +pub mod prelude; +pub mod register; + +pub use crate::peripheral::Peripherals; diff --git a/src/rust/vendor/cortex-m/src/macros.rs b/src/rust/vendor/cortex-m/src/macros.rs new file mode 100644 index 000000000..512c93234 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/macros.rs @@ -0,0 +1,114 @@ +/// Macro for sending a formatted string through an ITM channel +#[macro_export] +macro_rules! iprint { + ($channel:expr, $s:expr) => { + $crate::itm::write_str($channel, $s); + }; + ($channel:expr, $($arg:tt)*) => { + $crate::itm::write_fmt($channel, format_args!($($arg)*)); + }; +} + +/// Macro for sending a formatted string through an ITM channel, with a newline. +#[macro_export] +macro_rules! iprintln { + ($channel:expr) => { + $crate::itm::write_str($channel, "\n"); + }; + ($channel:expr, $fmt:expr) => { + $crate::itm::write_str($channel, concat!($fmt, "\n")); + }; + ($channel:expr, $fmt:expr, $($arg:tt)*) => { + $crate::itm::write_fmt($channel, format_args!(concat!($fmt, "\n"), $($arg)*)); + }; +} + +/// Macro to create a mutable reference to a statically allocated value +/// +/// This macro returns a value with type `Option<&'static mut $ty>`. `Some($expr)` will be returned +/// the first time the macro is executed; further calls will return `None`. To avoid `unwrap`ping a +/// `None` variant the caller must ensure that the macro is called from a function that's executed +/// at most once in the whole lifetime of the program. +/// +/// # Notes +/// This macro is unsound on multi core systems. +/// +/// For debuggability, you can set an explicit name for a singleton. This name only shows up the +/// the debugger and is not referencable from other code. See example below. +/// +/// # Example +/// +/// ``` no_run +/// use cortex_m::singleton; +/// +/// fn main() { +/// // OK if `main` is executed only once +/// let x: &'static mut bool = singleton!(: bool = false).unwrap(); +/// +/// let y = alias(); +/// // BAD this second call to `alias` will definitively `panic!` +/// let y_alias = alias(); +/// } +/// +/// fn alias() -> &'static mut bool { +/// singleton!(: bool = false).unwrap() +/// } +/// +/// fn singleton_with_name() { +/// // A name only for debugging purposes +/// singleton!(FOO_BUFFER: [u8; 1024] = [0u8; 1024]); +/// } +/// ``` +#[macro_export] +macro_rules! singleton { + ($name:ident: $ty:ty = $expr:expr) => { + $crate::interrupt::free(|_| { + // this is a tuple of a MaybeUninit and a bool because using an Option here is + // problematic: Due to niche-optimization, an Option could end up producing a non-zero + // initializer value which would move the entire static from `.bss` into `.data`... + static mut $name: (::core::mem::MaybeUninit<$ty>, bool) = + (::core::mem::MaybeUninit::uninit(), false); + + #[allow(unsafe_code)] + let used = unsafe { $name.1 }; + if used { + None + } else { + let expr = $expr; + + #[allow(unsafe_code)] + unsafe { + $name.1 = true; + $name.0 = ::core::mem::MaybeUninit::new(expr); + Some(&mut *$name.0.as_mut_ptr()) + } + } + }) + }; + (: $ty:ty = $expr:expr) => { + $crate::singleton!(VAR: $ty = $expr) + }; +} + +/// ``` compile_fail +/// use cortex_m::singleton; +/// +/// fn foo() { +/// // check that the call to `uninitialized` requires unsafe +/// singleton!(: u8 = std::mem::uninitialized()); +/// } +/// ``` +#[allow(dead_code)] +const CFAIL: () = (); + +/// ``` +/// #![deny(unsafe_code)] +/// use cortex_m::singleton; +/// +/// fn foo() { +/// // check that calls to `singleton!` don't trip the `unsafe_code` lint +/// singleton!(: u8 = 0); +/// } +/// ``` +#[allow(dead_code)] +const CPASS: () = (); diff --git a/src/rust/vendor/cortex-m/src/peripheral/ac.rs b/src/rust/vendor/cortex-m/src/peripheral/ac.rs new file mode 100644 index 000000000..1ac5be108 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/ac.rs @@ -0,0 +1,93 @@ +//! Cortex-M7 TCM and Cache access control. + +use volatile_register::RW; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Instruction Tightly-Coupled Memory Control Register + pub itcmcr: RW, + /// Data Tightly-Coupled Memory Control Register + pub dtcmcr: RW, + /// AHBP Control Register + pub ahbpcr: RW, + /// L1 Cache Control Register + pub cacr: RW, + /// AHB Slave Control Register + pub ahbscr: RW, + reserved0: u32, + /// Auxilary Bus Fault Status Register + pub abfsr: RW, +} + +/// ITCMCR and DTCMCR TCM enable bit. +pub const TCM_EN: u32 = 1; + +/// ITCMCR and DTCMCR TCM read-modify-write bit. +pub const TCM_RMW: u32 = 2; + +/// ITCMCR and DTCMCR TCM rety phase enable bit. +pub const TCM_RETEN: u32 = 4; + +/// ITCMCR and DTCMCR TCM size mask. +pub const TCM_SZ_MASK: u32 = 0x78; + +/// ITCMCR and DTCMCR TCM shift. +pub const TCM_SZ_SHIFT: usize = 3; + +/// AHBPCR AHBP enable bit. +pub const AHBPCR_EN: u32 = 1; + +/// AHBPCR AHBP size mask. +pub const AHBPCR_SZ_MASK: u32 = 0x0e; + +/// AHBPCR AHBP size shit. +pub const AHBPCR_SZ_SHIFT: usize = 1; + +/// CACR Shared cachedable-is-WT for data cache. +pub const CACR_SIWT: u32 = 1; + +/// CACR ECC in the instruction and data cache (disable). +pub const CACR_ECCDIS: u32 = 2; + +/// CACR Force Write-Through in the data cache. +pub const CACR_FORCEWT: u32 = 4; + +/// AHBSCR AHBS prioritization control mask. +pub const AHBSCR_CTL_MASK: u32 = 0x03; + +/// AHBSCR AHBS prioritization control shift. +pub const AHBSCR_CTL_SHIFT: usize = 0; + +/// AHBSCR Threshold execution prioity for AHBS traffic demotion, mask. +pub const AHBSCR_TPRI_MASK: u32 = 0x7fc; + +/// AHBSCR Threshold execution prioity for AHBS traffic demotion, shift. +pub const AHBSCR_TPRI_SHIFT: usize = 2; + +/// AHBSCR Failness counter initialization value, mask. +pub const AHBSCR_INITCOUNT_MASK: u32 = 0xf800; + +/// AHBSCR Failness counter initialization value, shift. +pub const AHBSCR_INITCOUNT_SHIFT: usize = 11; + +/// ABFSR Async fault on ITCM interface. +pub const ABFSR_ITCM: u32 = 1; + +/// ABFSR Async fault on DTCM interface. +pub const ABFSR_DTCM: u32 = 2; + +/// ABFSR Async fault on AHBP interface. +pub const ABFSR_AHBP: u32 = 4; + +/// ABFSR Async fault on AXIM interface. +pub const ABFSR_AXIM: u32 = 8; + +/// ABFSR Async fault on EPPB interface. +pub const ABFSR_EPPB: u32 = 16; + +/// ABFSR Indicates the type of fault on the AXIM interface, mask. +pub const ABFSR_AXIMTYPE_MASK: u32 = 0x300; + +/// ABFSR Indicates the type of fault on the AXIM interface, shift. +pub const ABFSR_AXIMTYPE_SHIFT: usize = 8; diff --git a/src/rust/vendor/cortex-m/src/peripheral/cbp.rs b/src/rust/vendor/cortex-m/src/peripheral/cbp.rs new file mode 100644 index 000000000..5aee5444b --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/cbp.rs @@ -0,0 +1,138 @@ +//! Cache and branch predictor maintenance operations +//! +//! *NOTE* Not available on Armv6-M. + +use volatile_register::WO; + +use crate::peripheral::CBP; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// I-cache invalidate all to PoU + pub iciallu: WO, + reserved0: u32, + /// I-cache invalidate by MVA to PoU + pub icimvau: WO, + /// D-cache invalidate by MVA to PoC + pub dcimvac: WO, + /// D-cache invalidate by set-way + pub dcisw: WO, + /// D-cache clean by MVA to PoU + pub dccmvau: WO, + /// D-cache clean by MVA to PoC + pub dccmvac: WO, + /// D-cache clean by set-way + pub dccsw: WO, + /// D-cache clean and invalidate by MVA to PoC + pub dccimvac: WO, + /// D-cache clean and invalidate by set-way + pub dccisw: WO, + /// Branch predictor invalidate all + pub bpiall: WO, +} + +const CBP_SW_WAY_POS: u32 = 30; +const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; +const CBP_SW_SET_POS: u32 = 5; +const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS; + +impl CBP { + /// I-cache invalidate all to PoU + #[inline(always)] + pub fn iciallu(&mut self) { + unsafe { self.iciallu.write(0) }; + } + + /// I-cache invalidate by MVA to PoU + #[inline(always)] + pub fn icimvau(&mut self, mva: u32) { + unsafe { self.icimvau.write(mva) }; + } + + /// D-cache invalidate by MVA to PoC + #[inline(always)] + pub unsafe fn dcimvac(&mut self, mva: u32) { + self.dcimvac.write(mva); + } + + /// D-cache invalidate by set-way + /// + /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. + #[inline(always)] + pub unsafe fn dcisw(&mut self, set: u16, way: u16) { + // The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way + // operations have a register data format which depends on the implementation's + // associativity and number of sets. Specifically the 'way' and 'set' fields have + // offsets 32-log2(ASSOCIATIVITY) and log2(LINELEN) respectively. + // + // However, in Cortex-M7 devices, these offsets are fixed at 30 and 5, as per the Cortex-M7 + // Generic User Guide section 4.8.3. Since no other ARMv7-M implementations except the + // Cortex-M7 have a DCACHE or ICACHE at all, it seems safe to do the same thing as the + // CMSIS-Core implementation and use fixed values. + self.dcisw.write( + ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) + | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS), + ); + } + + /// D-cache clean by MVA to PoU + #[inline(always)] + pub fn dccmvau(&mut self, mva: u32) { + unsafe { + self.dccmvau.write(mva); + } + } + + /// D-cache clean by MVA to PoC + #[inline(always)] + pub fn dccmvac(&mut self, mva: u32) { + unsafe { + self.dccmvac.write(mva); + } + } + + /// D-cache clean by set-way + /// + /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. + #[inline(always)] + pub fn dccsw(&mut self, set: u16, way: u16) { + // See comment for dcisw() about the format here + unsafe { + self.dccsw.write( + ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) + | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS), + ); + } + } + + /// D-cache clean and invalidate by MVA to PoC + #[inline(always)] + pub fn dccimvac(&mut self, mva: u32) { + unsafe { + self.dccimvac.write(mva); + } + } + + /// D-cache clean and invalidate by set-way + /// + /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. + #[inline(always)] + pub fn dccisw(&mut self, set: u16, way: u16) { + // See comment for dcisw() about the format here + unsafe { + self.dccisw.write( + ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) + | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS), + ); + } + } + + /// Branch predictor invalidate all + #[inline(always)] + pub fn bpiall(&mut self) { + unsafe { + self.bpiall.write(0); + } + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/cpuid.rs b/src/rust/vendor/cortex-m/src/peripheral/cpuid.rs new file mode 100644 index 000000000..db85566ea --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/cpuid.rs @@ -0,0 +1,140 @@ +//! CPUID + +use volatile_register::RO; +#[cfg(not(armv6m))] +use volatile_register::RW; + +#[cfg(not(armv6m))] +use crate::peripheral::CPUID; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// CPUID base + pub base: RO, + + _reserved0: [u32; 15], + + /// Processor Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub pfr: [RO; 2], + #[cfg(armv6m)] + _reserved1: [u32; 2], + + /// Debug Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub dfr: RO, + #[cfg(armv6m)] + _reserved2: u32, + + /// Auxiliary Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub afr: RO, + #[cfg(armv6m)] + _reserved3: u32, + + /// Memory Model Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub mmfr: [RO; 4], + #[cfg(armv6m)] + _reserved4: [u32; 4], + + /// Instruction Set Attribute (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub isar: [RO; 5], + #[cfg(armv6m)] + _reserved5: [u32; 5], + + _reserved6: u32, + + /// Cache Level ID (only present on Cortex-M7) + #[cfg(not(armv6m))] + pub clidr: RO, + + /// Cache Type (only present on Cortex-M7) + #[cfg(not(armv6m))] + pub ctr: RO, + + /// Cache Size ID (only present on Cortex-M7) + #[cfg(not(armv6m))] + pub ccsidr: RO, + + /// Cache Size Selection (only present on Cortex-M7) + #[cfg(not(armv6m))] + pub csselr: RW, +} + +/// Type of cache to select on CSSELR writes. +#[cfg(not(armv6m))] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum CsselrCacheType { + /// Select DCache or unified cache + DataOrUnified = 0, + /// Select ICache + Instruction = 1, +} + +#[cfg(not(armv6m))] +impl CPUID { + /// Selects the current CCSIDR + /// + /// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2 + /// * `ind`: select instruction cache or data/unified cache + /// + /// `level` is masked to be between 0 and 7. + #[inline] + pub fn select_cache(&mut self, level: u8, ind: CsselrCacheType) { + const CSSELR_IND_POS: u32 = 0; + const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS; + const CSSELR_LEVEL_POS: u32 = 1; + const CSSELR_LEVEL_MASK: u32 = 0x7 << CSSELR_LEVEL_POS; + + unsafe { + self.csselr.write( + ((u32::from(level) << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK) + | (((ind as u32) << CSSELR_IND_POS) & CSSELR_IND_MASK), + ) + } + } + + /// Returns the number of sets and ways in the selected cache + #[inline] + pub fn cache_num_sets_ways(&mut self, level: u8, ind: CsselrCacheType) -> (u16, u16) { + const CCSIDR_NUMSETS_POS: u32 = 13; + const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; + const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; + const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS; + + self.select_cache(level, ind); + crate::asm::dsb(); + let ccsidr = self.ccsidr.read(); + ( + (1 + ((ccsidr & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS)) as u16, + (1 + ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS)) as u16, + ) + } + + /// Returns log2 of the number of words in the smallest cache line of all the data cache and + /// unified caches that are controlled by the processor. + /// + /// This is the `DminLine` field of the CTR register. + #[inline(always)] + pub fn cache_dminline() -> u32 { + const CTR_DMINLINE_POS: u32 = 16; + const CTR_DMINLINE_MASK: u32 = 0xF << CTR_DMINLINE_POS; + let ctr = unsafe { (*Self::PTR).ctr.read() }; + (ctr & CTR_DMINLINE_MASK) >> CTR_DMINLINE_POS + } + + /// Returns log2 of the number of words in the smallest cache line of all the instruction + /// caches that are controlled by the processor. + /// + /// This is the `IminLine` field of the CTR register. + #[inline(always)] + pub fn cache_iminline() -> u32 { + const CTR_IMINLINE_POS: u32 = 0; + const CTR_IMINLINE_MASK: u32 = 0xF << CTR_IMINLINE_POS; + let ctr = unsafe { (*Self::PTR).ctr.read() }; + (ctr & CTR_IMINLINE_MASK) >> CTR_IMINLINE_POS + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/dcb.rs b/src/rust/vendor/cortex-m/src/peripheral/dcb.rs new file mode 100644 index 000000000..4a63c8895 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/dcb.rs @@ -0,0 +1,60 @@ +//! Debug Control Block + +use volatile_register::{RW, WO}; + +use crate::peripheral::DCB; +use core::ptr; + +const DCB_DEMCR_TRCENA: u32 = 1 << 24; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Debug Halting Control and Status + pub dhcsr: RW, + /// Debug Core Register Selector + pub dcrsr: WO, + /// Debug Core Register Data + pub dcrdr: RW, + /// Debug Exception and Monitor Control + pub demcr: RW, +} + +impl DCB { + /// Enables TRACE. This is for example required by the + /// `peripheral::DWT` cycle counter to work properly. + /// As by STM documentation, this flag is not reset on + /// soft-reset, only on power reset. + #[inline] + pub fn enable_trace(&mut self) { + // set bit 24 / TRCENA + unsafe { + self.demcr.modify(|w| w | DCB_DEMCR_TRCENA); + } + } + + /// Disables TRACE. See `DCB::enable_trace()` for more details + #[inline] + pub fn disable_trace(&mut self) { + // unset bit 24 / TRCENA + unsafe { + self.demcr.modify(|w| w & !DCB_DEMCR_TRCENA); + } + } + + /// Is there a debugger attached? (see note) + /// + /// Note: This function is [reported not to + /// work](http://web.archive.org/web/20180821191012/https://community.nxp.com/thread/424925#comment-782843) + /// on Cortex-M0 devices. Per the ARM v6-M Architecture Reference Manual, "Access to the DHCSR + /// from software running on the processor is IMPLEMENTATION DEFINED". Indeed, from the + /// [Cortex-M0+ r0p1 Technical Reference Manual](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0484c/BABJHEIG.html), "Note Software cannot access the debug registers." + #[inline] + pub fn is_debugger_attached() -> bool { + unsafe { + // do an 8-bit read of the 32-bit DHCSR register, and get the LSB + let value = ptr::read_volatile(Self::PTR as *const u8); + value & 0x1 == 1 + } + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/dwt.rs b/src/rust/vendor/cortex-m/src/peripheral/dwt.rs new file mode 100644 index 000000000..58d91fd3b --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/dwt.rs @@ -0,0 +1,268 @@ +//! Data Watchpoint and Trace unit + +#[cfg(not(armv6m))] +use volatile_register::WO; +use volatile_register::{RO, RW}; + +use crate::peripheral::DWT; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Control + pub ctrl: RW, + /// Cycle Count + #[cfg(not(armv6m))] + pub cyccnt: RW, + /// CPI Count + #[cfg(not(armv6m))] + pub cpicnt: RW, + /// Exception Overhead Count + #[cfg(not(armv6m))] + pub exccnt: RW, + /// Sleep Count + #[cfg(not(armv6m))] + pub sleepcnt: RW, + /// LSU Count + #[cfg(not(armv6m))] + pub lsucnt: RW, + /// Folded-instruction Count + #[cfg(not(armv6m))] + pub foldcnt: RW, + /// Cortex-M0(+) does not have these parts + #[cfg(armv6m)] + reserved: [u32; 6], + /// Program Counter Sample + pub pcsr: RO, + /// Comparators + #[cfg(armv6m)] + pub c: [Comparator; 2], + #[cfg(not(armv6m))] + /// Comparators + pub c: [Comparator; 16], + #[cfg(not(armv6m))] + reserved: [u32; 932], + /// Lock Access + #[cfg(not(armv6m))] + pub lar: WO, + /// Lock Status + #[cfg(not(armv6m))] + pub lsr: RO, +} + +/// Comparator +#[repr(C)] +pub struct Comparator { + /// Comparator + pub comp: RW, + /// Comparator Mask + pub mask: RW, + /// Comparator Function + pub function: RW, + reserved: u32, +} + +// DWT CTRL register fields +const NUMCOMP_OFFSET: u32 = 28; +const NOTRCPKT: u32 = 1 << 27; +const NOEXTTRIG: u32 = 1 << 26; +const NOCYCCNT: u32 = 1 << 25; +const NOPRFCNT: u32 = 1 << 24; +const CYCCNTENA: u32 = 1 << 0; + +impl DWT { + /// Number of comparators implemented + /// + /// A value of zero indicates no comparator support. + #[inline] + pub fn num_comp() -> u8 { + // NOTE(unsafe) atomic read with no side effects + unsafe { ((*Self::PTR).ctrl.read() >> NUMCOMP_OFFSET) as u8 } + } + + /// Returns `true` if the the implementation supports sampling and exception tracing + #[cfg(not(armv6m))] + #[inline] + pub fn has_exception_trace() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).ctrl.read() & NOTRCPKT == 0 } + } + + /// Returns `true` if the implementation includes external match signals + #[cfg(not(armv6m))] + #[inline] + pub fn has_external_match() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).ctrl.read() & NOEXTTRIG == 0 } + } + + /// Returns `true` if the implementation supports a cycle counter + #[cfg(not(armv6m))] + #[inline] + pub fn has_cycle_counter() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).ctrl.read() & NOCYCCNT == 0 } + } + + /// Returns `true` if the implementation the profiling counters + #[cfg(not(armv6m))] + #[inline] + pub fn has_profiling_counter() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).ctrl.read() & NOPRFCNT == 0 } + } + + /// Enables the cycle counter + /// + /// The global trace enable ([`DCB::enable_trace`]) should be set before + /// enabling the cycle counter, the processor may ignore writes to the + /// cycle counter enable if the global trace is disabled + /// (implementation defined behaviour). + /// + /// [`DCB::enable_trace`]: crate::peripheral::DCB::enable_trace + #[cfg(not(armv6m))] + #[inline] + pub fn enable_cycle_counter(&mut self) { + unsafe { self.ctrl.modify(|r| r | CYCCNTENA) } + } + + /// Disables the cycle counter + #[cfg(not(armv6m))] + #[inline] + pub fn disable_cycle_counter(&mut self) { + unsafe { self.ctrl.modify(|r| r & !CYCCNTENA) } + } + + /// Returns `true` if the cycle counter is enabled + #[cfg(not(armv6m))] + #[inline] + pub fn cycle_counter_enabled() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).ctrl.read() & CYCCNTENA != 0 } + } + + /// Returns the current clock cycle count + #[cfg(not(armv6m))] + #[inline] + #[deprecated( + since = "0.7.4", + note = "Use `cycle_count` which follows the C-GETTER convention" + )] + pub fn get_cycle_count() -> u32 { + Self::cycle_count() + } + + /// Returns the current clock cycle count + #[cfg(not(armv6m))] + #[inline] + pub fn cycle_count() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).cyccnt.read() } + } + + /// Set the cycle count + #[cfg(not(armv6m))] + #[inline] + pub fn set_cycle_count(&mut self, count: u32) { + unsafe { self.cyccnt.write(count) } + } + + /// Removes the software lock on the DWT + /// + /// Some devices, like the STM32F7, software lock the DWT after a power cycle. + #[cfg(not(armv6m))] + #[inline] + pub fn unlock() { + // NOTE(unsafe) atomic write to a stateless, write-only register + unsafe { (*Self::PTR).lar.write(0xC5AC_CE55) } + } + + /// Get the CPI count + /// + /// Counts additional cycles required to execute multi-cycle instructions, + /// except those recorded by [`lsu_count`], and counts any instruction fetch + /// stalls. + /// + /// [`lsu_count`]: DWT::lsu_count + #[cfg(not(armv6m))] + #[inline] + pub fn cpi_count() -> u8 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).cpicnt.read() as u8 } + } + + /// Set the CPI count + #[cfg(not(armv6m))] + #[inline] + pub fn set_cpi_count(&mut self, count: u8) { + unsafe { self.cpicnt.write(count as u32) } + } + + /// Get the total cycles spent in exception processing + #[cfg(not(armv6m))] + #[inline] + pub fn exception_count() -> u8 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).exccnt.read() as u8 } + } + + /// Set the exception count + #[cfg(not(armv6m))] + #[inline] + pub fn set_exception_count(&mut self, count: u8) { + unsafe { self.exccnt.write(count as u32) } + } + + /// Get the total number of cycles that the processor is sleeping + /// + /// ARM recommends that this counter counts all cycles when the processor is sleeping, + /// regardless of whether a WFI or WFE instruction, or the sleep-on-exit functionality, + /// caused the entry to sleep mode. + /// However, all sleep features are implementation defined and therefore when + /// this counter counts is implementation defined. + #[cfg(not(armv6m))] + #[inline] + pub fn sleep_count() -> u8 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).sleepcnt.read() as u8 } + } + + /// Set the sleep count + #[cfg(not(armv6m))] + #[inline] + pub fn set_sleep_count(&mut self, count: u8) { + unsafe { self.sleepcnt.write(count as u32) } + } + + /// Get the additional cycles required to execute all load or store instructions + #[cfg(not(armv6m))] + #[inline] + pub fn lsu_count() -> u8 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).lsucnt.read() as u8 } + } + + /// Set the lsu count + #[cfg(not(armv6m))] + #[inline] + pub fn set_lsu_count(&mut self, count: u8) { + unsafe { self.lsucnt.write(count as u32) } + } + + /// Get the folded instruction count + /// + /// Increments on each instruction that takes 0 cycles. + #[cfg(not(armv6m))] + #[inline] + pub fn fold_count() -> u8 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).foldcnt.read() as u8 } + } + + /// Set the folded instruction count + #[cfg(not(armv6m))] + #[inline] + pub fn set_fold_count(&mut self, count: u8) { + unsafe { self.foldcnt.write(count as u32) } + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/fpb.rs b/src/rust/vendor/cortex-m/src/peripheral/fpb.rs new file mode 100644 index 000000000..b86b8b2bd --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/fpb.rs @@ -0,0 +1,21 @@ +//! Flash Patch and Breakpoint unit +//! +//! *NOTE* Not available on Armv6-M. + +use volatile_register::{RO, RW, WO}; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Control + pub ctrl: RW, + /// Remap + pub remap: RW, + /// Comparator + pub comp: [RW; 127], + reserved: [u32; 875], + /// Lock Access + pub lar: WO, + /// Lock Status + pub lsr: RO, +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/fpu.rs b/src/rust/vendor/cortex-m/src/peripheral/fpu.rs new file mode 100644 index 000000000..9a047d86c --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/fpu.rs @@ -0,0 +1,19 @@ +//! Floating Point Unit +//! +//! *NOTE* Available only on targets with a Floating Point Unit (FPU) extension. + +use volatile_register::{RO, RW}; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + reserved: u32, + /// Floating Point Context Control + pub fpccr: RW, + /// Floating Point Context Address + pub fpcar: RW, + /// Floating Point Default Status Control + pub fpdscr: RW, + /// Media and FP Feature + pub mvfr: [RO; 3], +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/icb.rs b/src/rust/vendor/cortex-m/src/peripheral/icb.rs new file mode 100644 index 000000000..e1de33b38 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/icb.rs @@ -0,0 +1,32 @@ +//! Implementation Control Block + +#[cfg(any(armv7m, armv8m, native))] +use volatile_register::RO; +use volatile_register::RW; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Interrupt Controller Type Register + /// + /// The bottom four bits of this register give the number of implemented + /// interrupt lines, divided by 32. So a value of `0b0010` indicates 64 + /// interrupts. + #[cfg(any(armv7m, armv8m, native))] + pub ictr: RO, + + /// The ICTR is not defined in the ARMv6-M Architecture Reference manual, so + /// we replace it with this. + #[cfg(not(any(armv7m, armv8m, native)))] + _reserved: u32, + + /// Auxiliary Control Register + /// + /// This register is entirely implementation defined -- the standard gives + /// it an address, but does not define its role or contents. + pub actlr: RW, + + /// Coprocessor Power Control Register + #[cfg(armv8m)] + pub cppwr: RW, +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/itm.rs b/src/rust/vendor/cortex-m/src/peripheral/itm.rs new file mode 100644 index 000000000..c0d560f5c --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/itm.rs @@ -0,0 +1,71 @@ +//! Instrumentation Trace Macrocell +//! +//! *NOTE* Not available on Armv6-M and Armv8-M Baseline. + +use core::cell::UnsafeCell; +use core::ptr; + +use volatile_register::{RO, RW, WO}; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Stimulus Port + pub stim: [Stim; 256], + reserved0: [u32; 640], + /// Trace Enable + pub ter: [RW; 8], + reserved1: [u32; 8], + /// Trace Privilege + pub tpr: RW, + reserved2: [u32; 15], + /// Trace Control + pub tcr: RW, + reserved3: [u32; 75], + /// Lock Access + pub lar: WO, + /// Lock Status + pub lsr: RO, +} + +/// Stimulus Port +pub struct Stim { + register: UnsafeCell, +} + +impl Stim { + /// Writes an `u8` payload into the stimulus port + #[inline] + pub fn write_u8(&mut self, value: u8) { + unsafe { ptr::write_volatile(self.register.get() as *mut u8, value) } + } + + /// Writes an `u16` payload into the stimulus port + #[inline] + pub fn write_u16(&mut self, value: u16) { + unsafe { ptr::write_volatile(self.register.get() as *mut u16, value) } + } + + /// Writes an `u32` payload into the stimulus port + #[inline] + pub fn write_u32(&mut self, value: u32) { + unsafe { ptr::write_volatile(self.register.get(), value) } + } + + /// Returns `true` if the stimulus port is ready to accept more data + #[cfg(not(armv8m))] + #[inline] + pub fn is_fifo_ready(&self) -> bool { + unsafe { ptr::read_volatile(self.register.get()) & 0b1 == 1 } + } + + /// Returns `true` if the stimulus port is ready to accept more data + #[cfg(armv8m)] + #[inline] + pub fn is_fifo_ready(&self) -> bool { + // ARMv8-M adds a disabled bit; we indicate that we are ready to + // proceed with a stimulus write if the port is either ready (bit 0) or + // disabled (bit 1). + unsafe { ptr::read_volatile(self.register.get()) & 0b11 != 0 } + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/mod.rs b/src/rust/vendor/cortex-m/src/peripheral/mod.rs new file mode 100644 index 000000000..d8fd2d465 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/mod.rs @@ -0,0 +1,685 @@ +//! Core peripherals. +//! +//! # API +//! +//! To use (most of) the peripheral API first you must get an *instance* of the peripheral. All the +//! core peripherals are modeled as singletons (there can only ever be, at most, one instance of any +//! one of them at any given point in time) and the only way to get an instance of them is through +//! the [`Peripherals::take`](struct.Peripherals.html#method.take) method. +//! +//! ``` no_run +//! # use cortex_m::peripheral::Peripherals; +//! let mut peripherals = Peripherals::take().unwrap(); +//! peripherals.DCB.enable_trace(); +//! ``` +//! +//! This method can only be successfully called *once* -- this is why the method returns an +//! `Option`. Subsequent calls to the method will result in a `None` value being returned. +//! +//! ``` no_run, should_panic +//! # use cortex_m::peripheral::Peripherals; +//! let ok = Peripherals::take().unwrap(); +//! let panics = Peripherals::take().unwrap(); +//! ``` +//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the +//! API is provided as static methods on the peripheral types. One example is the +//! [`DWT::cycle_count`](struct.DWT.html#method.cycle_count) method. +//! +//! ``` no_run +//! # use cortex_m::peripheral::{DWT, Peripherals}; +//! { +//! let mut peripherals = Peripherals::take().unwrap(); +//! peripherals.DCB.enable_trace(); +//! peripherals.DWT.enable_cycle_counter(); +//! } // all the peripheral singletons are destroyed here +//! +//! // but this method can be called without a DWT instance +//! let cyccnt = DWT::cycle_count(); +//! ``` +//! +//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is +//! available on all the peripheral types. This method is a useful building block for implementing +//! safe higher level abstractions. +//! +//! ``` no_run +//! # use cortex_m::peripheral::{DWT, Peripherals}; +//! { +//! let mut peripherals = Peripherals::take().unwrap(); +//! peripherals.DCB.enable_trace(); +//! peripherals.DWT.enable_cycle_counter(); +//! } // all the peripheral singletons are destroyed here +//! +//! // actually safe because this is an atomic read with no side effects +//! let cyccnt = unsafe { (*DWT::PTR).cyccnt.read() }; +//! ``` +//! +//! # References +//! +//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3 + +use core::marker::PhantomData; +use core::ops; + +use crate::interrupt; + +#[cfg(cm7)] +pub mod ac; +#[cfg(not(armv6m))] +pub mod cbp; +pub mod cpuid; +pub mod dcb; +pub mod dwt; +#[cfg(not(armv6m))] +pub mod fpb; +// NOTE(native) is for documentation purposes +#[cfg(any(has_fpu, native))] +pub mod fpu; +pub mod icb; +#[cfg(all(not(armv6m), not(armv8m_base)))] +pub mod itm; +pub mod mpu; +pub mod nvic; +#[cfg(armv8m)] +pub mod sau; +pub mod scb; +pub mod syst; +#[cfg(not(armv6m))] +pub mod tpiu; + +#[cfg(test)] +mod test; + +// NOTE the `PhantomData` used in the peripherals proxy is to make them `Send` but *not* `Sync` + +/// Core peripherals +#[allow(non_snake_case)] +#[allow(clippy::manual_non_exhaustive)] +pub struct Peripherals { + /// Cortex-M7 TCM and cache access control. + #[cfg(cm7)] + pub AC: AC, + + /// Cache and branch predictor maintenance operations. + /// Not available on Armv6-M. + pub CBP: CBP, + + /// CPUID + pub CPUID: CPUID, + + /// Debug Control Block + pub DCB: DCB, + + /// Data Watchpoint and Trace unit + pub DWT: DWT, + + /// Flash Patch and Breakpoint unit. + /// Not available on Armv6-M. + pub FPB: FPB, + + /// Floating Point Unit. + pub FPU: FPU, + + /// Implementation Control Block. + /// + /// The name is from the v8-M spec, but the block existed in earlier + /// revisions, without a name. + pub ICB: ICB, + + /// Instrumentation Trace Macrocell. + /// Not available on Armv6-M and Armv8-M Baseline. + pub ITM: ITM, + + /// Memory Protection Unit + pub MPU: MPU, + + /// Nested Vector Interrupt Controller + pub NVIC: NVIC, + + /// Security Attribution Unit + pub SAU: SAU, + + /// System Control Block + pub SCB: SCB, + + /// SysTick: System Timer + pub SYST: SYST, + + /// Trace Port Interface Unit. + /// Not available on Armv6-M. + pub TPIU: TPIU, + + // Private field making `Peripherals` non-exhaustive. We don't use `#[non_exhaustive]` so we + // can support older Rust versions. + _priv: (), +} + +// NOTE `no_mangle` is used here to prevent linking different minor versions of this crate as that +// would let you `take` the core peripherals more than once (one per minor version) +#[no_mangle] +static CORE_PERIPHERALS: () = (); + +/// Set to `true` when `take` or `steal` was called to make `Peripherals` a singleton. +static mut TAKEN: bool = false; + +impl Peripherals { + /// Returns all the core peripherals *once* + #[inline] + pub fn take() -> Option { + interrupt::free(|_| { + if unsafe { TAKEN } { + None + } else { + Some(unsafe { Peripherals::steal() }) + } + }) + } + + /// Unchecked version of `Peripherals::take` + #[inline] + pub unsafe fn steal() -> Self { + TAKEN = true; + + Peripherals { + #[cfg(cm7)] + AC: AC { + _marker: PhantomData, + }, + CBP: CBP { + _marker: PhantomData, + }, + CPUID: CPUID { + _marker: PhantomData, + }, + DCB: DCB { + _marker: PhantomData, + }, + DWT: DWT { + _marker: PhantomData, + }, + FPB: FPB { + _marker: PhantomData, + }, + FPU: FPU { + _marker: PhantomData, + }, + ICB: ICB { + _marker: PhantomData, + }, + ITM: ITM { + _marker: PhantomData, + }, + MPU: MPU { + _marker: PhantomData, + }, + NVIC: NVIC { + _marker: PhantomData, + }, + SAU: SAU { + _marker: PhantomData, + }, + SCB: SCB { + _marker: PhantomData, + }, + SYST: SYST { + _marker: PhantomData, + }, + TPIU: TPIU { + _marker: PhantomData, + }, + _priv: (), + } + } +} + +/// Access control +#[cfg(cm7)] +pub struct AC { + _marker: PhantomData<*const ()>, +} + +#[cfg(cm7)] +unsafe impl Send for AC {} + +#[cfg(cm7)] +impl AC { + /// Pointer to the register block + pub const PTR: *const self::ac::RegisterBlock = 0xE000_EF90 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const self::ac::RegisterBlock { + Self::PTR + } +} + +/// Cache and branch predictor maintenance operations +pub struct CBP { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for CBP {} + +#[cfg(not(armv6m))] +impl CBP { + #[inline(always)] + pub(crate) const unsafe fn new() -> Self { + CBP { + _marker: PhantomData, + } + } + + /// Pointer to the register block + pub const PTR: *const self::cbp::RegisterBlock = 0xE000_EF50 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const self::cbp::RegisterBlock { + Self::PTR + } +} + +#[cfg(not(armv6m))] +impl ops::Deref for CBP { + type Target = self::cbp::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// CPUID +pub struct CPUID { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for CPUID {} + +impl CPUID { + /// Pointer to the register block + pub const PTR: *const self::cpuid::RegisterBlock = 0xE000_ED00 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const self::cpuid::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for CPUID { + type Target = self::cpuid::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// Debug Control Block +pub struct DCB { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for DCB {} + +impl DCB { + /// Pointer to the register block + pub const PTR: *const dcb::RegisterBlock = 0xE000_EDF0 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const dcb::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for DCB { + type Target = self::dcb::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*DCB::PTR } + } +} + +/// Data Watchpoint and Trace unit +pub struct DWT { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for DWT {} + +impl DWT { + /// Pointer to the register block + pub const PTR: *const dwt::RegisterBlock = 0xE000_1000 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const dwt::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for DWT { + type Target = self::dwt::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// Flash Patch and Breakpoint unit +pub struct FPB { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for FPB {} + +#[cfg(not(armv6m))] +impl FPB { + /// Pointer to the register block + pub const PTR: *const fpb::RegisterBlock = 0xE000_2000 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const fpb::RegisterBlock { + Self::PTR + } +} + +#[cfg(not(armv6m))] +impl ops::Deref for FPB { + type Target = self::fpb::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// Floating Point Unit +pub struct FPU { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for FPU {} + +#[cfg(any(has_fpu, native))] +impl FPU { + /// Pointer to the register block + pub const PTR: *const fpu::RegisterBlock = 0xE000_EF30 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const fpu::RegisterBlock { + Self::PTR + } +} + +#[cfg(any(has_fpu, native))] +impl ops::Deref for FPU { + type Target = self::fpu::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// Implementation Control Block. +/// +/// This block contains implementation-defined registers like `ictr` and +/// `actlr`. It's called the "implementation control block" in the ARMv8-M +/// standard, but earlier standards contained the registers, just without a +/// name. +pub struct ICB { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for ICB {} + +impl ICB { + /// Pointer to the register block + pub const PTR: *mut icb::RegisterBlock = 0xE000_E004 as *mut _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *mut icb::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for ICB { + type Target = self::icb::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +impl ops::DerefMut for ICB { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *Self::PTR } + } +} + +/// Instrumentation Trace Macrocell +pub struct ITM { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for ITM {} + +#[cfg(all(not(armv6m), not(armv8m_base)))] +impl ITM { + /// Pointer to the register block + pub const PTR: *mut itm::RegisterBlock = 0xE000_0000 as *mut _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *mut itm::RegisterBlock { + Self::PTR + } +} + +#[cfg(all(not(armv6m), not(armv8m_base)))] +impl ops::Deref for ITM { + type Target = self::itm::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +#[cfg(all(not(armv6m), not(armv8m_base)))] +impl ops::DerefMut for ITM { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *Self::PTR } + } +} + +/// Memory Protection Unit +pub struct MPU { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for MPU {} + +impl MPU { + /// Pointer to the register block + pub const PTR: *const mpu::RegisterBlock = 0xE000_ED90 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const mpu::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for MPU { + type Target = self::mpu::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// Nested Vector Interrupt Controller +pub struct NVIC { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for NVIC {} + +impl NVIC { + /// Pointer to the register block + pub const PTR: *const nvic::RegisterBlock = 0xE000_E100 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const nvic::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for NVIC { + type Target = self::nvic::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// Security Attribution Unit +pub struct SAU { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for SAU {} + +#[cfg(armv8m)] +impl SAU { + /// Pointer to the register block + pub const PTR: *const sau::RegisterBlock = 0xE000_EDD0 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const sau::RegisterBlock { + Self::PTR + } +} + +#[cfg(armv8m)] +impl ops::Deref for SAU { + type Target = self::sau::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// System Control Block +pub struct SCB { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for SCB {} + +impl SCB { + /// Pointer to the register block + pub const PTR: *const scb::RegisterBlock = 0xE000_ED04 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const scb::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for SCB { + type Target = self::scb::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// SysTick: System Timer +pub struct SYST { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for SYST {} + +impl SYST { + /// Pointer to the register block + pub const PTR: *const syst::RegisterBlock = 0xE000_E010 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const syst::RegisterBlock { + Self::PTR + } +} + +impl ops::Deref for SYST { + type Target = self::syst::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} + +/// Trace Port Interface Unit +pub struct TPIU { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for TPIU {} + +#[cfg(not(armv6m))] +impl TPIU { + /// Pointer to the register block + pub const PTR: *const tpiu::RegisterBlock = 0xE004_0000 as *const _; + + /// Returns a pointer to the register block + #[inline(always)] + #[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")] + pub const fn ptr() -> *const tpiu::RegisterBlock { + Self::PTR + } +} + +#[cfg(not(armv6m))] +impl ops::Deref for TPIU { + type Target = self::tpiu::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/mpu.rs b/src/rust/vendor/cortex-m/src/peripheral/mpu.rs new file mode 100644 index 000000000..3a5f5b4d9 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/mpu.rs @@ -0,0 +1,65 @@ +//! Memory Protection Unit + +use volatile_register::{RO, RW}; + +/// Register block for ARMv7-M +#[cfg(not(armv8m))] +#[repr(C)] +pub struct RegisterBlock { + /// Type + pub _type: RO, + /// Control + pub ctrl: RW, + /// Region Number + pub rnr: RW, + /// Region Base Address + pub rbar: RW, + /// Region Attribute and Size + pub rasr: RW, + /// Alias 1 of RBAR + pub rbar_a1: RW, + /// Alias 1 of RASR + pub rasr_a1: RW, + /// Alias 2 of RBAR + pub rbar_a2: RW, + /// Alias 2 of RASR + pub rasr_a2: RW, + /// Alias 3 of RBAR + pub rbar_a3: RW, + /// Alias 3 of RASR + pub rasr_a3: RW, +} + +/// Register block for ARMv8-M +#[cfg(armv8m)] +#[repr(C)] +pub struct RegisterBlock { + /// Type + pub _type: RO, + /// Control + pub ctrl: RW, + /// Region Number + pub rnr: RW, + /// Region Base Address + pub rbar: RW, + /// Region Limit Address + pub rlar: RW, + /// Alias 1 of RBAR + pub rbar_a1: RW, + /// Alias 1 of RLAR + pub rlar_a1: RW, + /// Alias 2 of RBAR + pub rbar_a2: RW, + /// Alias 2 of RLAR + pub rlar_a2: RW, + /// Alias 3 of RBAR + pub rbar_a3: RW, + /// Alias 3 of RLAR + pub rlar_a3: RW, + + // Reserved word at offset 0xBC + _reserved: u32, + + /// Memory Attribute Indirection register 0 and 1 + pub mair: [RW; 2], +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/nvic.rs b/src/rust/vendor/cortex-m/src/peripheral/nvic.rs new file mode 100644 index 000000000..57fa94b70 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/nvic.rs @@ -0,0 +1,265 @@ +//! Nested Vector Interrupt Controller + +use volatile_register::RW; +#[cfg(not(armv6m))] +use volatile_register::{RO, WO}; + +use crate::interrupt::InterruptNumber; +use crate::peripheral::NVIC; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Interrupt Set-Enable + pub iser: [RW; 16], + + _reserved0: [u32; 16], + + /// Interrupt Clear-Enable + pub icer: [RW; 16], + + _reserved1: [u32; 16], + + /// Interrupt Set-Pending + pub ispr: [RW; 16], + + _reserved2: [u32; 16], + + /// Interrupt Clear-Pending + pub icpr: [RW; 16], + + _reserved3: [u32; 16], + + /// Interrupt Active Bit (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub iabr: [RO; 16], + #[cfg(armv6m)] + _reserved4: [u32; 16], + + _reserved5: [u32; 48], + + /// Interrupt Priority + /// + /// On ARMv7-M, 124 word-sized registers are available. Each of those + /// contains of 4 interrupt priorities of 8 byte each.The architecture + /// specifically allows accessing those along byte boundaries, so they are + /// represented as 496 byte-sized registers, for convenience, and to allow + /// atomic priority updates. + /// + /// On ARMv6-M, the registers must only be accessed along word boundaries, + /// so convenient byte-sized representation wouldn't work on that + /// architecture. + #[cfg(not(armv6m))] + pub ipr: [RW; 496], + + /// Interrupt Priority + /// + /// On ARMv7-M, 124 word-sized registers are available. Each of those + /// contains of 4 interrupt priorities of 8 byte each.The architecture + /// specifically allows accessing those along byte boundaries, so they are + /// represented as 496 byte-sized registers, for convenience, and to allow + /// atomic priority updates. + /// + /// On ARMv6-M, the registers must only be accessed along word boundaries, + /// so convenient byte-sized representation wouldn't work on that + /// architecture. + #[cfg(armv6m)] + pub ipr: [RW; 8], + + #[cfg(not(armv6m))] + _reserved6: [u32; 580], + + /// Software Trigger Interrupt + #[cfg(not(armv6m))] + pub stir: WO, +} + +impl NVIC { + /// Request an IRQ in software + /// + /// Writing a value to the INTID field is the same as manually pending an interrupt by setting + /// the corresponding interrupt bit in an Interrupt Set Pending Register. This is similar to + /// [`NVIC::pend`]. + /// + /// This method is not available on ARMv6-M chips. + /// + /// [`NVIC::pend`]: #method.pend + #[cfg(not(armv6m))] + #[inline] + pub fn request(&mut self, interrupt: I) + where + I: InterruptNumber, + { + let nr = interrupt.number(); + + unsafe { + self.stir.write(u32::from(nr)); + } + } + + /// Disables `interrupt` + #[inline] + pub fn mask(interrupt: I) + where + I: InterruptNumber, + { + let nr = interrupt.number(); + // NOTE(unsafe) this is a write to a stateless register + unsafe { (*Self::PTR).icer[usize::from(nr / 32)].write(1 << (nr % 32)) } + } + + /// Enables `interrupt` + /// + /// This function is `unsafe` because it can break mask-based critical sections + #[inline] + pub unsafe fn unmask(interrupt: I) + where + I: InterruptNumber, + { + let nr = interrupt.number(); + // NOTE(ptr) this is a write to a stateless register + (*Self::PTR).iser[usize::from(nr / 32)].write(1 << (nr % 32)) + } + + /// Returns the NVIC priority of `interrupt` + /// + /// *NOTE* NVIC encodes priority in the highest bits of a byte so values like `1` and `2` map + /// to the same priority. Also for NVIC priorities, a lower value (e.g. `16`) has higher + /// priority (urgency) than a larger value (e.g. `32`). + #[inline] + pub fn get_priority(interrupt: I) -> u8 + where + I: InterruptNumber, + { + #[cfg(not(armv6m))] + { + let nr = interrupt.number(); + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).ipr[usize::from(nr)].read() } + } + + #[cfg(armv6m)] + { + // NOTE(unsafe) atomic read with no side effects + let ipr_n = unsafe { (*Self::PTR).ipr[Self::ipr_index(interrupt)].read() }; + let prio = (ipr_n >> Self::ipr_shift(interrupt)) & 0x0000_00ff; + prio as u8 + } + } + + /// Is `interrupt` active or pre-empted and stacked + #[cfg(not(armv6m))] + #[inline] + pub fn is_active(interrupt: I) -> bool + where + I: InterruptNumber, + { + let nr = interrupt.number(); + let mask = 1 << (nr % 32); + + // NOTE(unsafe) atomic read with no side effects + unsafe { ((*Self::PTR).iabr[usize::from(nr / 32)].read() & mask) == mask } + } + + /// Checks if `interrupt` is enabled + #[inline] + pub fn is_enabled(interrupt: I) -> bool + where + I: InterruptNumber, + { + let nr = interrupt.number(); + let mask = 1 << (nr % 32); + + // NOTE(unsafe) atomic read with no side effects + unsafe { ((*Self::PTR).iser[usize::from(nr / 32)].read() & mask) == mask } + } + + /// Checks if `interrupt` is pending + #[inline] + pub fn is_pending(interrupt: I) -> bool + where + I: InterruptNumber, + { + let nr = interrupt.number(); + let mask = 1 << (nr % 32); + + // NOTE(unsafe) atomic read with no side effects + unsafe { ((*Self::PTR).ispr[usize::from(nr / 32)].read() & mask) == mask } + } + + /// Forces `interrupt` into pending state + #[inline] + pub fn pend(interrupt: I) + where + I: InterruptNumber, + { + let nr = interrupt.number(); + + // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state + unsafe { (*Self::PTR).ispr[usize::from(nr / 32)].write(1 << (nr % 32)) } + } + + /// Sets the "priority" of `interrupt` to `prio` + /// + /// *NOTE* See [`get_priority`](struct.NVIC.html#method.get_priority) method for an explanation + /// of how NVIC priorities work. + /// + /// On ARMv6-M, updating an interrupt priority requires a read-modify-write operation. On + /// ARMv7-M, the operation is performed in a single atomic write operation. + /// + /// # Unsafety + /// + /// Changing priority levels can break priority-based critical sections (see + /// [`register::basepri`](crate::register::basepri)) and compromise memory safety. + #[inline] + pub unsafe fn set_priority(&mut self, interrupt: I, prio: u8) + where + I: InterruptNumber, + { + #[cfg(not(armv6m))] + { + let nr = interrupt.number(); + self.ipr[usize::from(nr)].write(prio) + } + + #[cfg(armv6m)] + { + self.ipr[Self::ipr_index(interrupt)].modify(|value| { + let mask = 0x0000_00ff << Self::ipr_shift(interrupt); + let prio = u32::from(prio) << Self::ipr_shift(interrupt); + + (value & !mask) | prio + }) + } + } + + /// Clears `interrupt`'s pending state + #[inline] + pub fn unpend(interrupt: I) + where + I: InterruptNumber, + { + let nr = interrupt.number(); + + // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state + unsafe { (*Self::PTR).icpr[usize::from(nr / 32)].write(1 << (nr % 32)) } + } + + #[cfg(armv6m)] + #[inline] + fn ipr_index(interrupt: I) -> usize + where + I: InterruptNumber, + { + usize::from(interrupt.number()) / 4 + } + + #[cfg(armv6m)] + #[inline] + fn ipr_shift(interrupt: I) -> usize + where + I: InterruptNumber, + { + (usize::from(interrupt.number()) % 4) * 8 + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/sau.rs b/src/rust/vendor/cortex-m/src/peripheral/sau.rs new file mode 100644 index 000000000..da91aca9b --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/sau.rs @@ -0,0 +1,243 @@ +//! Security Attribution Unit +//! +//! *NOTE* Available only on Armv8-M and Armv8.1-M, for the following Rust target triples: +//! * `thumbv8m.base-none-eabi` +//! * `thumbv8m.main-none-eabi` +//! * `thumbv8m.main-none-eabihf` +//! +//! For reference please check the section B8.3 of the Armv8-M Architecture Reference Manual. + +use crate::interrupt; +use crate::peripheral::SAU; +use bitfield::bitfield; +use volatile_register::{RO, RW}; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Control Register + pub ctrl: RW, + /// Type Register + pub _type: RO, + /// Region Number Register + pub rnr: RW, + /// Region Base Address Register + pub rbar: RW, + /// Region Limit Address Register + pub rlar: RW, + /// Secure Fault Status Register + pub sfsr: RO, + /// Secure Fault Address Register + pub sfar: RO, +} + +bitfield! { + /// Control Register description + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Ctrl(u32); + get_enable, set_enable: 0; + get_allns, set_allns: 1; +} + +bitfield! { + /// Type Register description + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Type(u32); + u8; + sregion, _: 7, 0; +} + +bitfield! { + /// Region Number Register description + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Rnr(u32); + u8; + get_region, set_region: 7, 0; +} + +bitfield! { + /// Region Base Address Register description + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Rbar(u32); + u32; + get_baddr, set_baddr: 31, 5; +} + +bitfield! { + /// Region Limit Address Register description + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Rlar(u32); + u32; + get_laddr, set_laddr: 31, 5; + get_nsc, set_nsc: 1; + get_enable, set_enable: 0; +} + +bitfield! { + /// Secure Fault Status Register description + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Sfsr(u32); + invep, _: 0; + invis, _: 1; + inver, _: 2; + auviol, _: 3; + invtran, _: 4; + lsperr, _: 5; + sfarvalid, _: 6; + lserr, _: 7; +} + +bitfield! { + /// Secure Fault Address Register description + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Sfar(u32); + u32; + address, _: 31, 0; +} + +/// Possible attribute of a SAU region. +#[derive(Debug)] +pub enum SauRegionAttribute { + /// SAU region is Secure + Secure, + /// SAU region is Non-Secure Callable + NonSecureCallable, + /// SAU region is Non-Secure + NonSecure, +} + +/// Description of a SAU region. +#[derive(Debug)] +pub struct SauRegion { + /// First address of the region, its 5 least significant bits must be set to zero. + pub base_address: u32, + /// Last address of the region, its 5 least significant bits must be set to one. + pub limit_address: u32, + /// Attribute of the region. + pub attribute: SauRegionAttribute, +} + +/// Possible error values returned by the SAU methods. +#[derive(Debug)] +pub enum SauError { + /// The region number parameter to set or get a region must be between 0 and + /// region_numbers() - 1. + RegionNumberTooBig, + /// Bits 0 to 4 of the base address of a SAU region must be set to zero. + WrongBaseAddress, + /// Bits 0 to 4 of the limit address of a SAU region must be set to one. + WrongLimitAddress, +} + +impl SAU { + /// Get the number of implemented SAU regions. + #[inline] + pub fn region_numbers(&self) -> u8 { + self._type.read().sregion() + } + + /// Enable the SAU. + #[inline] + pub fn enable(&mut self) { + unsafe { + self.ctrl.modify(|mut ctrl| { + ctrl.set_enable(true); + ctrl + }); + } + } + + /// Set a SAU region to a region number. + /// SAU regions must be 32 bytes aligned and their sizes must be a multiple of 32 bytes. It + /// means that the 5 least significant bits of the base address of a SAU region must be set to + /// zero and the 5 least significant bits of the limit address must be set to one. + /// The region number must be valid. + /// This function is executed under a critical section to prevent having inconsistent results. + #[inline] + pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> { + interrupt::free(|_| { + let base_address = region.base_address; + let limit_address = region.limit_address; + let attribute = region.attribute; + + if region_number >= self.region_numbers() { + Err(SauError::RegionNumberTooBig) + } else if base_address & 0x1F != 0 { + Err(SauError::WrongBaseAddress) + } else if limit_address & 0x1F != 0x1F { + Err(SauError::WrongLimitAddress) + } else { + // All fields of these registers are going to be modified so we don't need to read them + // before. + let mut rnr = Rnr(0); + let mut rbar = Rbar(0); + let mut rlar = Rlar(0); + + rnr.set_region(region_number); + rbar.set_baddr(base_address >> 5); + rlar.set_laddr(limit_address >> 5); + + match attribute { + SauRegionAttribute::Secure => { + rlar.set_nsc(false); + rlar.set_enable(false); + } + SauRegionAttribute::NonSecureCallable => { + rlar.set_nsc(true); + rlar.set_enable(true); + } + SauRegionAttribute::NonSecure => { + rlar.set_nsc(false); + rlar.set_enable(true); + } + } + + unsafe { + self.rnr.write(rnr); + self.rbar.write(rbar); + self.rlar.write(rlar); + } + + Ok(()) + } + }) + } + + /// Get a region from the SAU. + /// The region number must be valid. + /// This function is executed under a critical section to prevent having inconsistent results. + #[inline] + pub fn get_region(&mut self, region_number: u8) -> Result { + interrupt::free(|_| { + if region_number >= self.region_numbers() { + Err(SauError::RegionNumberTooBig) + } else { + unsafe { + self.rnr.write(Rnr(region_number.into())); + } + + let rbar = self.rbar.read(); + let rlar = self.rlar.read(); + + let attribute = match (rlar.get_enable(), rlar.get_nsc()) { + (false, _) => SauRegionAttribute::Secure, + (true, false) => SauRegionAttribute::NonSecure, + (true, true) => SauRegionAttribute::NonSecureCallable, + }; + + Ok(SauRegion { + base_address: rbar.get_baddr() << 5, + limit_address: (rlar.get_laddr() << 5) | 0x1F, + attribute, + }) + } + }) + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/scb.rs b/src/rust/vendor/cortex-m/src/peripheral/scb.rs new file mode 100644 index 000000000..f998b17c5 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/scb.rs @@ -0,0 +1,1109 @@ +//! System Control Block + +use core::ptr; + +use volatile_register::RW; + +#[cfg(not(armv6m))] +use super::cpuid::CsselrCacheType; +#[cfg(not(armv6m))] +use super::CBP; +#[cfg(not(armv6m))] +use super::CPUID; +use super::SCB; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Interrupt Control and State + pub icsr: RW, + + /// Vector Table Offset (not present on Cortex-M0 variants) + pub vtor: RW, + + /// Application Interrupt and Reset Control + pub aircr: RW, + + /// System Control + pub scr: RW, + + /// Configuration and Control + pub ccr: RW, + + /// System Handler Priority (word accessible only on Cortex-M0 variants) + /// + /// On ARMv7-M, `shpr[0]` points to SHPR1 + /// + /// On ARMv6-M, `shpr[0]` points to SHPR2 + #[cfg(not(armv6m))] + pub shpr: [RW; 12], + #[cfg(armv6m)] + _reserved1: u32, + /// System Handler Priority (word accessible only on Cortex-M0 variants) + /// + /// On ARMv7-M, `shpr[0]` points to SHPR1 + /// + /// On ARMv6-M, `shpr[0]` points to SHPR2 + #[cfg(armv6m)] + pub shpr: [RW; 2], + + /// System Handler Control and State + pub shcsr: RW, + + /// Configurable Fault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub cfsr: RW, + #[cfg(armv6m)] + _reserved2: u32, + + /// HardFault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub hfsr: RW, + #[cfg(armv6m)] + _reserved3: u32, + + /// Debug Fault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub dfsr: RW, + #[cfg(armv6m)] + _reserved4: u32, + + /// MemManage Fault Address (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub mmfar: RW, + #[cfg(armv6m)] + _reserved5: u32, + + /// BusFault Address (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub bfar: RW, + #[cfg(armv6m)] + _reserved6: u32, + + /// Auxiliary Fault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub afsr: RW, + #[cfg(armv6m)] + _reserved7: u32, + + _reserved8: [u32; 18], + + /// Coprocessor Access Control (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub cpacr: RW, + #[cfg(armv6m)] + _reserved9: u32, +} + +/// FPU access mode +#[cfg(has_fpu)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FpuAccessMode { + /// FPU is not accessible + Disabled, + /// FPU is accessible in Privileged and User mode + Enabled, + /// FPU is accessible in Privileged mode only + Privileged, +} + +#[cfg(has_fpu)] +mod fpu_consts { + pub const SCB_CPACR_FPU_MASK: u32 = 0b11_11 << 20; + pub const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20; + pub const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20; +} + +#[cfg(has_fpu)] +use self::fpu_consts::*; + +#[cfg(has_fpu)] +impl SCB { + /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Disabled)` + #[inline] + pub fn disable_fpu(&mut self) { + self.set_fpu_access_mode(FpuAccessMode::Disabled) + } + + /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Enabled)` + #[inline] + pub fn enable_fpu(&mut self) { + self.set_fpu_access_mode(FpuAccessMode::Enabled) + } + + /// Gets FPU access mode + #[inline] + pub fn fpu_access_mode() -> FpuAccessMode { + // NOTE(unsafe) atomic read operation with no side effects + let cpacr = unsafe { (*Self::PTR).cpacr.read() }; + + if cpacr & SCB_CPACR_FPU_MASK == SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER { + FpuAccessMode::Enabled + } else if cpacr & SCB_CPACR_FPU_MASK == SCB_CPACR_FPU_ENABLE { + FpuAccessMode::Privileged + } else { + FpuAccessMode::Disabled + } + } + + /// Sets FPU access mode + /// + /// *IMPORTANT* Any function that runs fully or partly with the FPU disabled must *not* take any + /// floating-point arguments or have any floating-point local variables. Because the compiler + /// might inline such a function into a caller that does have floating-point arguments or + /// variables, any such function must be also marked #[inline(never)]. + #[inline] + pub fn set_fpu_access_mode(&mut self, mode: FpuAccessMode) { + let mut cpacr = self.cpacr.read() & !SCB_CPACR_FPU_MASK; + match mode { + FpuAccessMode::Disabled => (), + FpuAccessMode::Privileged => cpacr |= SCB_CPACR_FPU_ENABLE, + FpuAccessMode::Enabled => cpacr |= SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER, + } + unsafe { self.cpacr.write(cpacr) } + } +} + +impl SCB { + /// Returns the active exception number + #[inline] + pub fn vect_active() -> VectActive { + let icsr = unsafe { ptr::read(&(*SCB::PTR).icsr as *const _ as *const u32) }; + + match icsr as u8 { + 0 => VectActive::ThreadMode, + 2 => VectActive::Exception(Exception::NonMaskableInt), + 3 => VectActive::Exception(Exception::HardFault), + #[cfg(not(armv6m))] + 4 => VectActive::Exception(Exception::MemoryManagement), + #[cfg(not(armv6m))] + 5 => VectActive::Exception(Exception::BusFault), + #[cfg(not(armv6m))] + 6 => VectActive::Exception(Exception::UsageFault), + #[cfg(any(armv8m, native))] + 7 => VectActive::Exception(Exception::SecureFault), + 11 => VectActive::Exception(Exception::SVCall), + #[cfg(not(armv6m))] + 12 => VectActive::Exception(Exception::DebugMonitor), + 14 => VectActive::Exception(Exception::PendSV), + 15 => VectActive::Exception(Exception::SysTick), + irqn => VectActive::Interrupt { irqn: irqn - 16 }, + } + } +} + +/// Processor core exceptions (internal interrupts) +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "std", derive(PartialOrd, Hash))] +pub enum Exception { + /// Non maskable interrupt + NonMaskableInt, + + /// Hard fault interrupt + HardFault, + + /// Memory management interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + MemoryManagement, + + /// Bus fault interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + BusFault, + + /// Usage fault interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + UsageFault, + + /// Secure fault interrupt (only on ARMv8-M) + #[cfg(any(armv8m, native))] + SecureFault, + + /// SV call interrupt + SVCall, + + /// Debug monitor interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + DebugMonitor, + + /// Pend SV interrupt + PendSV, + + /// System Tick interrupt + SysTick, +} + +impl Exception { + /// Returns the IRQ number of this `Exception` + /// + /// The return value is always within the closed range `[-1, -14]` + #[inline] + pub fn irqn(self) -> i8 { + match self { + Exception::NonMaskableInt => -14, + Exception::HardFault => -13, + #[cfg(not(armv6m))] + Exception::MemoryManagement => -12, + #[cfg(not(armv6m))] + Exception::BusFault => -11, + #[cfg(not(armv6m))] + Exception::UsageFault => -10, + #[cfg(any(armv8m, native))] + Exception::SecureFault => -9, + Exception::SVCall => -5, + #[cfg(not(armv6m))] + Exception::DebugMonitor => -4, + Exception::PendSV => -2, + Exception::SysTick => -1, + } + } +} + +/// Active exception number +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "std", derive(PartialOrd, Hash))] +pub enum VectActive { + /// Thread mode + ThreadMode, + + /// Processor core exception (internal interrupts) + Exception(Exception), + + /// Device specific exception (external interrupts) + Interrupt { + /// Interrupt number. This number is always within half open range `[0, 240)` + irqn: u8, + }, +} + +impl VectActive { + /// Converts a `byte` into `VectActive` + #[inline] + pub fn from(vect_active: u8) -> Option { + Some(match vect_active { + 0 => VectActive::ThreadMode, + 2 => VectActive::Exception(Exception::NonMaskableInt), + 3 => VectActive::Exception(Exception::HardFault), + #[cfg(not(armv6m))] + 4 => VectActive::Exception(Exception::MemoryManagement), + #[cfg(not(armv6m))] + 5 => VectActive::Exception(Exception::BusFault), + #[cfg(not(armv6m))] + 6 => VectActive::Exception(Exception::UsageFault), + #[cfg(any(armv8m, native))] + 7 => VectActive::Exception(Exception::SecureFault), + 11 => VectActive::Exception(Exception::SVCall), + #[cfg(not(armv6m))] + 12 => VectActive::Exception(Exception::DebugMonitor), + 14 => VectActive::Exception(Exception::PendSV), + 15 => VectActive::Exception(Exception::SysTick), + irqn if irqn >= 16 => VectActive::Interrupt { irqn }, + _ => return None, + }) + } +} + +#[cfg(not(armv6m))] +mod scb_consts { + pub const SCB_CCR_IC_MASK: u32 = 1 << 17; + pub const SCB_CCR_DC_MASK: u32 = 1 << 16; +} + +#[cfg(not(armv6m))] +use self::scb_consts::*; + +#[cfg(not(armv6m))] +impl SCB { + /// Enables I-cache if currently disabled. + /// + /// This operation first invalidates the entire I-cache. + #[inline] + pub fn enable_icache(&mut self) { + // Don't do anything if I-cache is already enabled + if Self::icache_enabled() { + return; + } + + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; + + // Invalidate I-cache + cbp.iciallu(); + + // Enable I-cache + extern "C" { + // see asm-v7m.s + fn __enable_icache(); + } + + // NOTE(unsafe): The asm routine manages exclusive access to the SCB + // registers and applies the proper barriers; it is technically safe on + // its own, and is only `unsafe` here because it's `extern "C"`. + unsafe { + __enable_icache(); + } + } + + /// Disables I-cache if currently enabled. + /// + /// This operation invalidates the entire I-cache after disabling. + #[inline] + pub fn disable_icache(&mut self) { + // Don't do anything if I-cache is already disabled + if !Self::icache_enabled() { + return; + } + + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; + + // Disable I-cache + // NOTE(unsafe): We have synchronised access by &mut self + unsafe { self.ccr.modify(|r| r & !SCB_CCR_IC_MASK) }; + + // Invalidate I-cache + cbp.iciallu(); + + crate::asm::dsb(); + crate::asm::isb(); + } + + /// Returns whether the I-cache is currently enabled. + #[inline(always)] + pub fn icache_enabled() -> bool { + crate::asm::dsb(); + crate::asm::isb(); + + // NOTE(unsafe): atomic read with no side effects + unsafe { (*Self::PTR).ccr.read() & SCB_CCR_IC_MASK == SCB_CCR_IC_MASK } + } + + /// Invalidates the entire I-cache. + #[inline] + pub fn invalidate_icache(&mut self) { + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; + + // Invalidate I-cache + cbp.iciallu(); + + crate::asm::dsb(); + crate::asm::isb(); + } + + /// Enables D-cache if currently disabled. + /// + /// This operation first invalidates the entire D-cache, ensuring it does + /// not contain stale values before being enabled. + #[inline] + pub fn enable_dcache(&mut self, cpuid: &mut CPUID) { + // Don't do anything if D-cache is already enabled + if Self::dcache_enabled() { + return; + } + + // Invalidate anything currently in the D-cache + unsafe { self.invalidate_dcache(cpuid) }; + + // Now turn on the D-cache + extern "C" { + // see asm-v7m.s + fn __enable_dcache(); + } + + // NOTE(unsafe): The asm routine manages exclusive access to the SCB + // registers and applies the proper barriers; it is technically safe on + // its own, and is only `unsafe` here because it's `extern "C"`. + unsafe { + __enable_dcache(); + } + } + + /// Disables D-cache if currently enabled. + /// + /// This operation subsequently cleans and invalidates the entire D-cache, + /// ensuring all contents are safely written back to main memory after disabling. + #[inline] + pub fn disable_dcache(&mut self, cpuid: &mut CPUID) { + // Don't do anything if D-cache is already disabled + if !Self::dcache_enabled() { + return; + } + + // Turn off the D-cache + // NOTE(unsafe): We have synchronised access by &mut self + unsafe { self.ccr.modify(|r| r & !SCB_CCR_DC_MASK) }; + + // Clean and invalidate whatever was left in it + self.clean_invalidate_dcache(cpuid); + } + + /// Returns whether the D-cache is currently enabled. + #[inline] + pub fn dcache_enabled() -> bool { + crate::asm::dsb(); + crate::asm::isb(); + + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).ccr.read() & SCB_CCR_DC_MASK == SCB_CCR_DC_MASK } + } + + /// Invalidates the entire D-cache. + /// + /// Note that calling this while the dcache is enabled will probably wipe out the + /// stack, depending on optimisations, therefore breaking returning to the call point. + /// + /// It's used immediately before enabling the dcache, but not exported publicly. + #[inline] + unsafe fn invalidate_dcache(&mut self, cpuid: &mut CPUID) { + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = CBP::new(); + + // Read number of sets and ways + let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); + + // Invalidate entire D-cache + for set in 0..sets { + for way in 0..ways { + cbp.dcisw(set, way); + } + } + + crate::asm::dsb(); + crate::asm::isb(); + } + + /// Cleans the entire D-cache. + /// + /// This function causes everything in the D-cache to be written back to main memory, + /// overwriting whatever is already there. + #[inline] + pub fn clean_dcache(&mut self, cpuid: &mut CPUID) { + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; + + // Read number of sets and ways + let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); + + for set in 0..sets { + for way in 0..ways { + cbp.dccsw(set, way); + } + } + + crate::asm::dsb(); + crate::asm::isb(); + } + + /// Cleans and invalidates the entire D-cache. + /// + /// This function causes everything in the D-cache to be written back to main memory, + /// and then marks the entire D-cache as invalid, causing future reads to first fetch + /// from main memory. + #[inline] + pub fn clean_invalidate_dcache(&mut self, cpuid: &mut CPUID) { + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; + + // Read number of sets and ways + let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); + + for set in 0..sets { + for way in 0..ways { + cbp.dccisw(set, way); + } + } + + crate::asm::dsb(); + crate::asm::isb(); + } + + /// Invalidates D-cache by address. + /// + /// * `addr`: The address to invalidate, which must be cache-line aligned. + /// * `size`: Number of bytes to invalidate, which must be a multiple of the cache line size. + /// + /// Invalidates D-cache cache lines, starting from the first line containing `addr`, + /// finishing once at least `size` bytes have been invalidated. + /// + /// Invalidation causes the next read access to memory to be fetched from main memory instead + /// of the cache. + /// + /// # Cache Line Sizes + /// + /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed + /// to 32 bytes, which means `addr` must be 32-byte aligned and `size` must be a multiple + /// of 32. At the time of writing, no other Cortex-M cores have data caches. + /// + /// If `addr` is not cache-line aligned, or `size` is not a multiple of the cache line size, + /// other data before or after the desired memory would also be invalidated, which can very + /// easily cause memory corruption and undefined behaviour. + /// + /// # Safety + /// + /// After invalidating, the next read of invalidated data will be from main memory. This may + /// cause recent writes to be lost, potentially including writes that initialized objects. + /// Therefore, this method may cause uninitialized memory or invalid values to be read, + /// resulting in undefined behaviour. You must ensure that main memory contains valid and + /// initialized values before invalidating. + /// + /// `addr` **must** be aligned to the size of the cache lines, and `size` **must** be a + /// multiple of the cache line size, otherwise this function will invalidate other memory, + /// easily leading to memory corruption and undefined behaviour. This precondition is checked + /// in debug builds using a `debug_assert!()`, but not checked in release builds to avoid + /// a runtime-dependent `panic!()` call. + #[inline] + pub unsafe fn invalidate_dcache_by_address(&mut self, addr: usize, size: usize) { + // No-op zero sized operations + if size == 0 { + return; + } + + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = CBP::new(); + + // dminline is log2(num words), so 2**dminline * 4 gives size in bytes + let dminline = CPUID::cache_dminline(); + let line_size = (1 << dminline) * 4; + + debug_assert!((addr & (line_size - 1)) == 0); + debug_assert!((size & (line_size - 1)) == 0); + + crate::asm::dsb(); + + // Find number of cache lines to invalidate + let num_lines = ((size - 1) / line_size) + 1; + + // Compute address of first cache line + let mask = 0xFFFF_FFFF - (line_size - 1); + let mut addr = addr & mask; + + for _ in 0..num_lines { + cbp.dcimvac(addr as u32); + addr += line_size; + } + + crate::asm::dsb(); + crate::asm::isb(); + } + + /// Invalidates an object from the D-cache. + /// + /// * `obj`: The object to invalidate. + /// + /// Invalidates D-cache starting from the first cache line containing `obj`, + /// continuing to invalidate cache lines until all of `obj` has been invalidated. + /// + /// Invalidation causes the next read access to memory to be fetched from main memory instead + /// of the cache. + /// + /// # Cache Line Sizes + /// + /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed + /// to 32 bytes, which means `obj` must be 32-byte aligned, and its size must be a multiple + /// of 32 bytes. At the time of writing, no other Cortex-M cores have data caches. + /// + /// If `obj` is not cache-line aligned, or its size is not a multiple of the cache line size, + /// other data before or after the desired memory would also be invalidated, which can very + /// easily cause memory corruption and undefined behaviour. + /// + /// # Safety + /// + /// After invalidating, `obj` will be read from main memory on next access. This may cause + /// recent writes to `obj` to be lost, potentially including the write that initialized it. + /// Therefore, this method may cause uninitialized memory or invalid values to be read, + /// resulting in undefined behaviour. You must ensure that main memory contains a valid and + /// initialized value for T before invalidating `obj`. + /// + /// `obj` **must** be aligned to the size of the cache lines, and its size **must** be a + /// multiple of the cache line size, otherwise this function will invalidate other memory, + /// easily leading to memory corruption and undefined behaviour. This precondition is checked + /// in debug builds using a `debug_assert!()`, but not checked in release builds to avoid + /// a runtime-dependent `panic!()` call. + #[inline] + pub unsafe fn invalidate_dcache_by_ref(&mut self, obj: &mut T) { + self.invalidate_dcache_by_address(obj as *const T as usize, core::mem::size_of::()); + } + + /// Invalidates a slice from the D-cache. + /// + /// * `slice`: The slice to invalidate. + /// + /// Invalidates D-cache starting from the first cache line containing members of `slice`, + /// continuing to invalidate cache lines until all of `slice` has been invalidated. + /// + /// Invalidation causes the next read access to memory to be fetched from main memory instead + /// of the cache. + /// + /// # Cache Line Sizes + /// + /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed + /// to 32 bytes, which means `slice` must be 32-byte aligned, and its size must be a multiple + /// of 32 bytes. At the time of writing, no other Cortex-M cores have data caches. + /// + /// If `slice` is not cache-line aligned, or its size is not a multiple of the cache line size, + /// other data before or after the desired memory would also be invalidated, which can very + /// easily cause memory corruption and undefined behaviour. + /// + /// # Safety + /// + /// After invalidating, `slice` will be read from main memory on next access. This may cause + /// recent writes to `slice` to be lost, potentially including the write that initialized it. + /// Therefore, this method may cause uninitialized memory or invalid values to be read, + /// resulting in undefined behaviour. You must ensure that main memory contains valid and + /// initialized values for T before invalidating `slice`. + /// + /// `slice` **must** be aligned to the size of the cache lines, and its size **must** be a + /// multiple of the cache line size, otherwise this function will invalidate other memory, + /// easily leading to memory corruption and undefined behaviour. This precondition is checked + /// in debug builds using a `debug_assert!()`, but not checked in release builds to avoid + /// a runtime-dependent `panic!()` call. + #[inline] + pub unsafe fn invalidate_dcache_by_slice(&mut self, slice: &mut [T]) { + self.invalidate_dcache_by_address( + slice.as_ptr() as usize, + slice.len() * core::mem::size_of::(), + ); + } + + /// Cleans D-cache by address. + /// + /// * `addr`: The address to start cleaning at. + /// * `size`: The number of bytes to clean. + /// + /// Cleans D-cache cache lines, starting from the first line containing `addr`, + /// finishing once at least `size` bytes have been invalidated. + /// + /// Cleaning the cache causes whatever data is present in the cache to be immediately written + /// to main memory, overwriting whatever was in main memory. + /// + /// # Cache Line Sizes + /// + /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed + /// to 32 bytes, which means `addr` should generally be 32-byte aligned and `size` should be a + /// multiple of 32. At the time of writing, no other Cortex-M cores have data caches. + /// + /// If `addr` is not cache-line aligned, or `size` is not a multiple of the cache line size, + /// other data before or after the desired memory will also be cleaned. From the point of view + /// of the core executing this function, memory remains consistent, so this is not unsound, + /// but is worth knowing about. + #[inline] + pub fn clean_dcache_by_address(&mut self, addr: usize, size: usize) { + // No-op zero sized operations + if size == 0 { + return; + } + + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; + + crate::asm::dsb(); + + let dminline = CPUID::cache_dminline(); + let line_size = (1 << dminline) * 4; + let num_lines = ((size - 1) / line_size) + 1; + + let mask = 0xFFFF_FFFF - (line_size - 1); + let mut addr = addr & mask; + + for _ in 0..num_lines { + cbp.dccmvac(addr as u32); + addr += line_size; + } + + crate::asm::dsb(); + crate::asm::isb(); + } + + /// Cleans an object from the D-cache. + /// + /// * `obj`: The object to clean. + /// + /// Cleans D-cache starting from the first cache line containing `obj`, + /// continuing to clean cache lines until all of `obj` has been cleaned. + /// + /// It is recommended that `obj` is both aligned to the cache line size and a multiple of + /// the cache line size long, otherwise surrounding data will also be cleaned. + /// + /// Cleaning the cache causes whatever data is present in the cache to be immediately written + /// to main memory, overwriting whatever was in main memory. + #[inline] + pub fn clean_dcache_by_ref(&mut self, obj: &T) { + self.clean_dcache_by_address(obj as *const T as usize, core::mem::size_of::()); + } + + /// Cleans a slice from D-cache. + /// + /// * `slice`: The slice to clean. + /// + /// Cleans D-cache starting from the first cache line containing members of `slice`, + /// continuing to clean cache lines until all of `slice` has been cleaned. + /// + /// It is recommended that `slice` is both aligned to the cache line size and a multiple of + /// the cache line size long, otherwise surrounding data will also be cleaned. + /// + /// Cleaning the cache causes whatever data is present in the cache to be immediately written + /// to main memory, overwriting whatever was in main memory. + #[inline] + pub fn clean_dcache_by_slice(&mut self, slice: &[T]) { + self.clean_dcache_by_address( + slice.as_ptr() as usize, + slice.len() * core::mem::size_of::(), + ); + } + + /// Cleans and invalidates D-cache by address. + /// + /// * `addr`: The address to clean and invalidate. + /// * `size`: The number of bytes to clean and invalidate. + /// + /// Cleans and invalidates D-cache starting from the first cache line containing `addr`, + /// finishing once at least `size` bytes have been cleaned and invalidated. + /// + /// It is recommended that `addr` is aligned to the cache line size and `size` is a multiple of + /// the cache line size, otherwise surrounding data will also be cleaned. + /// + /// Cleaning and invalidating causes data in the D-cache to be written back to main memory, + /// and then marks that data in the D-cache as invalid, causing future reads to first fetch + /// from main memory. + #[inline] + pub fn clean_invalidate_dcache_by_address(&mut self, addr: usize, size: usize) { + // No-op zero sized operations + if size == 0 { + return; + } + + // NOTE(unsafe): No races as all CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; + + crate::asm::dsb(); + + // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M + const LINESIZE: usize = 32; + let num_lines = ((size - 1) / LINESIZE) + 1; + + let mut addr = addr & 0xFFFF_FFE0; + + for _ in 0..num_lines { + cbp.dccimvac(addr as u32); + addr += LINESIZE; + } + + crate::asm::dsb(); + crate::asm::isb(); + } +} + +const SCB_SCR_SLEEPDEEP: u32 = 0x1 << 2; + +impl SCB { + /// Set the SLEEPDEEP bit in the SCR register + #[inline] + pub fn set_sleepdeep(&mut self) { + unsafe { + self.scr.modify(|scr| scr | SCB_SCR_SLEEPDEEP); + } + } + + /// Clear the SLEEPDEEP bit in the SCR register + #[inline] + pub fn clear_sleepdeep(&mut self) { + unsafe { + self.scr.modify(|scr| scr & !SCB_SCR_SLEEPDEEP); + } + } +} + +const SCB_SCR_SLEEPONEXIT: u32 = 0x1 << 1; + +impl SCB { + /// Set the SLEEPONEXIT bit in the SCR register + #[inline] + pub fn set_sleeponexit(&mut self) { + unsafe { + self.scr.modify(|scr| scr | SCB_SCR_SLEEPONEXIT); + } + } + + /// Clear the SLEEPONEXIT bit in the SCR register + #[inline] + pub fn clear_sleeponexit(&mut self) { + unsafe { + self.scr.modify(|scr| scr & !SCB_SCR_SLEEPONEXIT); + } + } +} + +const SCB_AIRCR_VECTKEY: u32 = 0x05FA << 16; +const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x7 << 8; +const SCB_AIRCR_SYSRESETREQ: u32 = 1 << 2; + +impl SCB { + /// Initiate a system reset request to reset the MCU + #[inline] + pub fn sys_reset() -> ! { + crate::asm::dsb(); + unsafe { + (*Self::PTR).aircr.modify( + |r| { + SCB_AIRCR_VECTKEY | // otherwise the write is ignored + r & SCB_AIRCR_PRIGROUP_MASK | // keep priority group unchanged + SCB_AIRCR_SYSRESETREQ + }, // set the bit + ) + }; + crate::asm::dsb(); + loop { + // wait for the reset + crate::asm::nop(); // avoid rust-lang/rust#28728 + } + } +} + +const SCB_ICSR_PENDSVSET: u32 = 1 << 28; +const SCB_ICSR_PENDSVCLR: u32 = 1 << 27; + +const SCB_ICSR_PENDSTSET: u32 = 1 << 26; +const SCB_ICSR_PENDSTCLR: u32 = 1 << 25; + +impl SCB { + /// Set the PENDSVSET bit in the ICSR register which will pend the PendSV interrupt + #[inline] + pub fn set_pendsv() { + unsafe { + (*Self::PTR).icsr.write(SCB_ICSR_PENDSVSET); + } + } + + /// Check if PENDSVSET bit in the ICSR register is set meaning PendSV interrupt is pending + #[inline] + pub fn is_pendsv_pending() -> bool { + unsafe { (*Self::PTR).icsr.read() & SCB_ICSR_PENDSVSET == SCB_ICSR_PENDSVSET } + } + + /// Set the PENDSVCLR bit in the ICSR register which will clear a pending PendSV interrupt + #[inline] + pub fn clear_pendsv() { + unsafe { + (*Self::PTR).icsr.write(SCB_ICSR_PENDSVCLR); + } + } + + /// Set the PENDSTSET bit in the ICSR register which will pend a SysTick interrupt + #[inline] + pub fn set_pendst() { + unsafe { + (*Self::PTR).icsr.write(SCB_ICSR_PENDSTSET); + } + } + + /// Check if PENDSTSET bit in the ICSR register is set meaning SysTick interrupt is pending + #[inline] + pub fn is_pendst_pending() -> bool { + unsafe { (*Self::PTR).icsr.read() & SCB_ICSR_PENDSTSET == SCB_ICSR_PENDSTSET } + } + + /// Set the PENDSTCLR bit in the ICSR register which will clear a pending SysTick interrupt + #[inline] + pub fn clear_pendst() { + unsafe { + (*Self::PTR).icsr.write(SCB_ICSR_PENDSTCLR); + } + } +} + +/// System handlers, exceptions with configurable priority +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] +pub enum SystemHandler { + // NonMaskableInt, // priority is fixed + // HardFault, // priority is fixed + /// Memory management interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + MemoryManagement = 4, + + /// Bus fault interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + BusFault = 5, + + /// Usage fault interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + UsageFault = 6, + + /// Secure fault interrupt (only on ARMv8-M) + #[cfg(any(armv8m, native))] + SecureFault = 7, + + /// SV call interrupt + SVCall = 11, + + /// Debug monitor interrupt (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + DebugMonitor = 12, + + /// Pend SV interrupt + PendSV = 14, + + /// System Tick interrupt + SysTick = 15, +} + +impl SCB { + /// Returns the hardware priority of `system_handler` + /// + /// *NOTE*: Hardware priority does not exactly match logical priority levels. See + /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details. + #[inline] + pub fn get_priority(system_handler: SystemHandler) -> u8 { + let index = system_handler as u8; + + #[cfg(not(armv6m))] + { + // NOTE(unsafe) atomic read with no side effects + + // NOTE(unsafe): Index is bounded to [4,15] by SystemHandler design. + // TODO: Review it after rust-lang/rust/issues/13926 will be fixed. + let priority_ref = unsafe { (*Self::PTR).shpr.get_unchecked(usize::from(index - 4)) }; + + priority_ref.read() + } + + #[cfg(armv6m)] + { + // NOTE(unsafe) atomic read with no side effects + + // NOTE(unsafe): Index is bounded to [11,15] by SystemHandler design. + // TODO: Review it after rust-lang/rust/issues/13926 will be fixed. + let priority_ref = unsafe { + (*Self::PTR) + .shpr + .get_unchecked(usize::from((index - 8) / 4)) + }; + + let shpr = priority_ref.read(); + let prio = (shpr >> (8 * (index % 4))) & 0x0000_00ff; + prio as u8 + } + } + + /// Sets the hardware priority of `system_handler` to `prio` + /// + /// *NOTE*: Hardware priority does not exactly match logical priority levels. See + /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details. + /// + /// On ARMv6-M, updating a system handler priority requires a read-modify-write operation. On + /// ARMv7-M, the operation is performed in a single, atomic write operation. + /// + /// # Unsafety + /// + /// Changing priority levels can break priority-based critical sections (see + /// [`register::basepri`](crate::register::basepri)) and compromise memory safety. + #[inline] + pub unsafe fn set_priority(&mut self, system_handler: SystemHandler, prio: u8) { + let index = system_handler as u8; + + #[cfg(not(armv6m))] + { + // NOTE(unsafe): Index is bounded to [4,15] by SystemHandler design. + // TODO: Review it after rust-lang/rust/issues/13926 will be fixed. + let priority_ref = (*Self::PTR).shpr.get_unchecked(usize::from(index - 4)); + + priority_ref.write(prio) + } + + #[cfg(armv6m)] + { + // NOTE(unsafe): Index is bounded to [11,15] by SystemHandler design. + // TODO: Review it after rust-lang/rust/issues/13926 will be fixed. + let priority_ref = (*Self::PTR) + .shpr + .get_unchecked(usize::from((index - 8) / 4)); + + priority_ref.modify(|value| { + let shift = 8 * (index % 4); + let mask = 0x0000_00ff << shift; + let prio = u32::from(prio) << shift; + + (value & !mask) | prio + }); + } + } + + /// Return the bit position of the exception enable bit in the SHCSR register + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + fn shcsr_enable_shift(exception: Exception) -> Option { + match exception { + Exception::MemoryManagement => Some(16), + Exception::BusFault => Some(17), + Exception::UsageFault => Some(18), + #[cfg(armv8m_main)] + Exception::SecureFault => Some(19), + _ => None, + } + } + + /// Enable the exception + /// + /// If the exception is enabled, when the exception is triggered, the exception handler will be executed instead of the + /// HardFault handler. + /// This function is only allowed on the following exceptions: + /// * `MemoryManagement` + /// * `BusFault` + /// * `UsageFault` + /// * `SecureFault` (can only be enabled from Secure state) + /// + /// Calling this function with any other exception will do nothing. + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + pub fn enable(&mut self, exception: Exception) { + if let Some(shift) = SCB::shcsr_enable_shift(exception) { + // The mutable reference to SCB makes sure that only this code is currently modifying + // the register. + unsafe { self.shcsr.modify(|value| value | (1 << shift)) } + } + } + + /// Disable the exception + /// + /// If the exception is disabled, when the exception is triggered, the HardFault handler will be executed instead of the + /// exception handler. + /// This function is only allowed on the following exceptions: + /// * `MemoryManagement` + /// * `BusFault` + /// * `UsageFault` + /// * `SecureFault` (can not be changed from Non-secure state) + /// + /// Calling this function with any other exception will do nothing. + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + pub fn disable(&mut self, exception: Exception) { + if let Some(shift) = SCB::shcsr_enable_shift(exception) { + // The mutable reference to SCB makes sure that only this code is currently modifying + // the register. + unsafe { self.shcsr.modify(|value| value & !(1 << shift)) } + } + } + + /// Check if an exception is enabled + /// + /// This function is only allowed on the following exception: + /// * `MemoryManagement` + /// * `BusFault` + /// * `UsageFault` + /// * `SecureFault` (can not be read from Non-secure state) + /// + /// Calling this function with any other exception will read `false`. + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + pub fn is_enabled(&self, exception: Exception) -> bool { + if let Some(shift) = SCB::shcsr_enable_shift(exception) { + (self.shcsr.read() & (1 << shift)) > 0 + } else { + false + } + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/syst.rs b/src/rust/vendor/cortex-m/src/peripheral/syst.rs new file mode 100644 index 000000000..345acc2ff --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/syst.rs @@ -0,0 +1,185 @@ +//! SysTick: System Timer + +use volatile_register::{RO, RW}; + +use crate::peripheral::SYST; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Control and Status + pub csr: RW, + /// Reload Value + pub rvr: RW, + /// Current Value + pub cvr: RW, + /// Calibration Value + pub calib: RO, +} + +/// SysTick clock source +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SystClkSource { + /// Core-provided clock + Core, + /// External reference clock + External, +} + +const SYST_COUNTER_MASK: u32 = 0x00ff_ffff; + +const SYST_CSR_ENABLE: u32 = 1 << 0; +const SYST_CSR_TICKINT: u32 = 1 << 1; +const SYST_CSR_CLKSOURCE: u32 = 1 << 2; +const SYST_CSR_COUNTFLAG: u32 = 1 << 16; + +const SYST_CALIB_SKEW: u32 = 1 << 30; +const SYST_CALIB_NOREF: u32 = 1 << 31; + +impl SYST { + /// Clears current value to 0 + /// + /// After calling `clear_current()`, the next call to `has_wrapped()` will return `false`. + #[inline] + pub fn clear_current(&mut self) { + unsafe { self.cvr.write(0) } + } + + /// Disables counter + #[inline] + pub fn disable_counter(&mut self) { + unsafe { self.csr.modify(|v| v & !SYST_CSR_ENABLE) } + } + + /// Disables SysTick interrupt + #[inline] + pub fn disable_interrupt(&mut self) { + unsafe { self.csr.modify(|v| v & !SYST_CSR_TICKINT) } + } + + /// Enables counter + /// + /// *NOTE* The reference manual indicates that: + /// + /// "The SysTick counter reload and current value are undefined at reset, the correct + /// initialization sequence for the SysTick counter is: + /// + /// - Program reload value + /// - Clear current value + /// - Program Control and Status register" + /// + /// The sequence translates to `self.set_reload(x); self.clear_current(); self.enable_counter()` + #[inline] + pub fn enable_counter(&mut self) { + unsafe { self.csr.modify(|v| v | SYST_CSR_ENABLE) } + } + + /// Enables SysTick interrupt + #[inline] + pub fn enable_interrupt(&mut self) { + unsafe { self.csr.modify(|v| v | SYST_CSR_TICKINT) } + } + + /// Gets clock source + /// + /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the + /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) + #[inline] + pub fn get_clock_source(&mut self) -> SystClkSource { + // NOTE(unsafe) atomic read with no side effects + if self.csr.read() & SYST_CSR_CLKSOURCE != 0 { + SystClkSource::Core + } else { + SystClkSource::External + } + } + + /// Gets current value + #[inline] + pub fn get_current() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).cvr.read() } + } + + /// Gets reload value + #[inline] + pub fn get_reload() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).rvr.read() } + } + + /// Returns the reload value with which the counter would wrap once per 10 + /// ms + /// + /// Returns `0` if the value is not known (e.g. because the clock can + /// change dynamically). + #[inline] + pub fn get_ticks_per_10ms() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).calib.read() & SYST_COUNTER_MASK } + } + + /// Checks if an external reference clock is available + #[inline] + pub fn has_reference_clock() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).calib.read() & SYST_CALIB_NOREF == 0 } + } + + /// Checks if the counter wrapped (underflowed) since the last check + /// + /// *NOTE* This takes `&mut self` because the read operation is side effectful and will clear + /// the bit of the read register. + #[inline] + pub fn has_wrapped(&mut self) -> bool { + self.csr.read() & SYST_CSR_COUNTFLAG != 0 + } + + /// Checks if counter is enabled + /// + /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the + /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) + #[inline] + pub fn is_counter_enabled(&mut self) -> bool { + self.csr.read() & SYST_CSR_ENABLE != 0 + } + + /// Checks if SysTick interrupt is enabled + /// + /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the + /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) + #[inline] + pub fn is_interrupt_enabled(&mut self) -> bool { + self.csr.read() & SYST_CSR_TICKINT != 0 + } + + /// Checks if the calibration value is precise + /// + /// Returns `false` if using the reload value returned by + /// `get_ticks_per_10ms()` may result in a period significantly deviating + /// from 10 ms. + #[inline] + pub fn is_precise() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::PTR).calib.read() & SYST_CALIB_SKEW == 0 } + } + + /// Sets clock source + #[inline] + pub fn set_clock_source(&mut self, clk_source: SystClkSource) { + match clk_source { + SystClkSource::External => unsafe { self.csr.modify(|v| v & !SYST_CSR_CLKSOURCE) }, + SystClkSource::Core => unsafe { self.csr.modify(|v| v | SYST_CSR_CLKSOURCE) }, + } + } + + /// Sets reload value + /// + /// Valid values are between `1` and `0x00ffffff`. + /// + /// *NOTE* To make the timer wrap every `N` ticks set the reload value to `N - 1` + #[inline] + pub fn set_reload(&mut self, value: u32) { + unsafe { self.rvr.write(value) } + } +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/test.rs b/src/rust/vendor/cortex-m/src/peripheral/test.rs new file mode 100644 index 000000000..cab064aad --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/test.rs @@ -0,0 +1,170 @@ +#[test] +fn cpuid() { + let cpuid = unsafe { &*crate::peripheral::CPUID::PTR }; + + assert_eq!(address(&cpuid.base), 0xE000_ED00); + assert_eq!(address(&cpuid.pfr), 0xE000_ED40); + assert_eq!(address(&cpuid.dfr), 0xE000_ED48); + assert_eq!(address(&cpuid.afr), 0xE000_ED4C); + assert_eq!(address(&cpuid.mmfr), 0xE000_ED50); + assert_eq!(address(&cpuid.isar), 0xE000_ED60); + assert_eq!(address(&cpuid.clidr), 0xE000_ED78); + assert_eq!(address(&cpuid.ctr), 0xE000_ED7C); + assert_eq!(address(&cpuid.ccsidr), 0xE000_ED80); + assert_eq!(address(&cpuid.csselr), 0xE000_ED84); +} + +#[test] +fn dcb() { + let dcb = unsafe { &*crate::peripheral::DCB::PTR }; + + assert_eq!(address(&dcb.dhcsr), 0xE000_EDF0); + assert_eq!(address(&dcb.dcrsr), 0xE000_EDF4); + assert_eq!(address(&dcb.dcrdr), 0xE000_EDF8); + assert_eq!(address(&dcb.demcr), 0xE000_EDFC); +} + +#[test] +fn dwt() { + let dwt = unsafe { &*crate::peripheral::DWT::PTR }; + + assert_eq!(address(&dwt.ctrl), 0xE000_1000); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.cyccnt), 0xE000_1004); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.cpicnt), 0xE000_1008); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.exccnt), 0xE000_100C); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.sleepcnt), 0xE000_1010); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.lsucnt), 0xE000_1014); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.foldcnt), 0xE000_1018); + assert_eq!(address(&dwt.pcsr), 0xE000_101C); + assert_eq!(address(&dwt.c[0].comp), 0xE000_1020); + assert_eq!(address(&dwt.c[0].mask), 0xE000_1024); + assert_eq!(address(&dwt.c[0].function), 0xE000_1028); + assert_eq!(address(&dwt.c[1].comp), 0xE000_1030); + assert_eq!(address(&dwt.c[1].mask), 0xE000_1034); + assert_eq!(address(&dwt.c[1].function), 0xE000_1038); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.lar), 0xE000_1FB0); + #[cfg(not(armv6m))] + assert_eq!(address(&dwt.lsr), 0xE000_1FB4); +} + +#[test] +fn fpb() { + let fpb = unsafe { &*crate::peripheral::FPB::PTR }; + + assert_eq!(address(&fpb.ctrl), 0xE000_2000); + assert_eq!(address(&fpb.remap), 0xE000_2004); + assert_eq!(address(&fpb.comp), 0xE000_2008); + assert_eq!(address(&fpb.comp[1]), 0xE000_200C); + assert_eq!(address(&fpb.lar), 0xE000_2FB0); + assert_eq!(address(&fpb.lsr), 0xE000_2FB4); +} + +#[test] +fn fpu() { + let fpu = unsafe { &*crate::peripheral::FPU::PTR }; + + assert_eq!(address(&fpu.fpccr), 0xE000_EF34); + assert_eq!(address(&fpu.fpcar), 0xE000_EF38); + assert_eq!(address(&fpu.fpdscr), 0xE000_EF3C); + assert_eq!(address(&fpu.mvfr), 0xE000_EF40); + assert_eq!(address(&fpu.mvfr[1]), 0xE000_EF44); + assert_eq!(address(&fpu.mvfr[2]), 0xE000_EF48); +} + +#[test] +fn itm() { + let itm = unsafe { &*crate::peripheral::ITM::PTR }; + + assert_eq!(address(&itm.stim), 0xE000_0000); + assert_eq!(address(&itm.ter), 0xE000_0E00); + assert_eq!(address(&itm.tpr), 0xE000_0E40); + assert_eq!(address(&itm.tcr), 0xE000_0E80); + assert_eq!(address(&itm.lar), 0xE000_0FB0); + assert_eq!(address(&itm.lsr), 0xE000_0FB4); +} + +#[test] +fn mpu() { + let mpu = unsafe { &*crate::peripheral::MPU::PTR }; + + assert_eq!(address(&mpu._type), 0xE000ED90); + assert_eq!(address(&mpu.ctrl), 0xE000ED94); + assert_eq!(address(&mpu.rnr), 0xE000ED98); + assert_eq!(address(&mpu.rbar), 0xE000ED9C); + assert_eq!(address(&mpu.rasr), 0xE000EDA0); + assert_eq!(address(&mpu.rbar_a1), 0xE000EDA4); + assert_eq!(address(&mpu.rasr_a1), 0xE000EDA8); + assert_eq!(address(&mpu.rbar_a2), 0xE000EDAC); + assert_eq!(address(&mpu.rasr_a2), 0xE000EDB0); + assert_eq!(address(&mpu.rbar_a3), 0xE000EDB4); + assert_eq!(address(&mpu.rasr_a3), 0xE000EDB8); +} + +#[test] +fn nvic() { + let nvic = unsafe { &*crate::peripheral::NVIC::PTR }; + + assert_eq!(address(&nvic.iser), 0xE000E100); + assert_eq!(address(&nvic.icer), 0xE000E180); + assert_eq!(address(&nvic.ispr), 0xE000E200); + assert_eq!(address(&nvic.icpr), 0xE000E280); + assert_eq!(address(&nvic.iabr), 0xE000E300); + assert_eq!(address(&nvic.ipr), 0xE000E400); + #[cfg(not(armv6m))] + assert_eq!(address(&nvic.stir), 0xE000EF00); +} + +#[test] +fn scb() { + let scb = unsafe { &*crate::peripheral::SCB::PTR }; + + assert_eq!(address(&scb.icsr), 0xE000_ED04); + assert_eq!(address(&scb.vtor), 0xE000_ED08); + assert_eq!(address(&scb.aircr), 0xE000_ED0C); + assert_eq!(address(&scb.scr), 0xE000_ED10); + assert_eq!(address(&scb.ccr), 0xE000_ED14); + assert_eq!(address(&scb.shpr), 0xE000_ED18); + assert_eq!(address(&scb.shcsr), 0xE000_ED24); + assert_eq!(address(&scb.cfsr), 0xE000_ED28); + assert_eq!(address(&scb.hfsr), 0xE000_ED2C); + assert_eq!(address(&scb.dfsr), 0xE000_ED30); + assert_eq!(address(&scb.mmfar), 0xE000_ED34); + assert_eq!(address(&scb.bfar), 0xE000_ED38); + assert_eq!(address(&scb.afsr), 0xE000_ED3C); + assert_eq!(address(&scb.cpacr), 0xE000_ED88); +} + +#[test] +fn syst() { + let syst = unsafe { &*crate::peripheral::SYST::PTR }; + + assert_eq!(address(&syst.csr), 0xE000_E010); + assert_eq!(address(&syst.rvr), 0xE000_E014); + assert_eq!(address(&syst.cvr), 0xE000_E018); + assert_eq!(address(&syst.calib), 0xE000_E01C); +} + +#[test] +fn tpiu() { + let tpiu = unsafe { &*crate::peripheral::TPIU::PTR }; + + assert_eq!(address(&tpiu.sspsr), 0xE004_0000); + assert_eq!(address(&tpiu.cspsr), 0xE004_0004); + assert_eq!(address(&tpiu.acpr), 0xE004_0010); + assert_eq!(address(&tpiu.sppr), 0xE004_00F0); + assert_eq!(address(&tpiu.ffcr), 0xE004_0304); + assert_eq!(address(&tpiu.lar), 0xE004_0FB0); + assert_eq!(address(&tpiu.lsr), 0xE004_0FB4); + assert_eq!(address(&tpiu._type), 0xE004_0FC8); +} + +fn address(r: *const T) -> usize { + r as usize +} diff --git a/src/rust/vendor/cortex-m/src/peripheral/tpiu.rs b/src/rust/vendor/cortex-m/src/peripheral/tpiu.rs new file mode 100644 index 000000000..11cb79e91 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/peripheral/tpiu.rs @@ -0,0 +1,31 @@ +//! Trace Port Interface Unit; +//! +//! *NOTE* Not available on Armv6-M. + +use volatile_register::{RO, RW, WO}; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Supported Parallel Port Sizes + pub sspsr: RO, + /// Current Parallel Port Size + pub cspsr: RW, + reserved0: [u32; 2], + /// Asynchronous Clock Prescaler + pub acpr: RW, + reserved1: [u32; 55], + /// Selected Pin Control + pub sppr: RW, + reserved2: [u32; 132], + /// Formatter and Flush Control + pub ffcr: RW, + reserved3: [u32; 810], + /// Lock Access + pub lar: WO, + /// Lock Status + pub lsr: RO, + reserved4: [u32; 4], + /// TPIU Type + pub _type: RO, +} diff --git a/src/rust/vendor/cortex-m/src/prelude.rs b/src/rust/vendor/cortex-m/src/prelude.rs new file mode 100644 index 000000000..bc47cc02e --- /dev/null +++ b/src/rust/vendor/cortex-m/src/prelude.rs @@ -0,0 +1,3 @@ +//! Prelude + +pub use embedded_hal::prelude::*; diff --git a/src/rust/vendor/cortex-m/src/register/apsr.rs b/src/rust/vendor/cortex-m/src/register/apsr.rs new file mode 100644 index 000000000..e83435cec --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/apsr.rs @@ -0,0 +1,54 @@ +//! Application Program Status Register + +/// Application Program Status Register +#[derive(Clone, Copy, Debug)] +pub struct Apsr { + bits: u32, +} + +impl Apsr { + /// Returns the contents of the register as raw bits + #[inline] + pub fn bits(self) -> u32 { + self.bits + } + + /// DSP overflow and saturation flag + #[inline] + pub fn q(self) -> bool { + self.bits & (1 << 27) == (1 << 27) + } + + /// Overflow flag + #[inline] + pub fn v(self) -> bool { + self.bits & (1 << 28) == (1 << 28) + } + + /// Carry or borrow flag + #[inline] + pub fn c(self) -> bool { + self.bits & (1 << 29) == (1 << 29) + } + + /// Zero flag + #[inline] + pub fn z(self) -> bool { + self.bits & (1 << 30) == (1 << 30) + } + + /// Negative flag + #[inline] + pub fn n(self) -> bool { + self.bits & (1 << 31) == (1 << 31) + } +} + +/// Reads the CPU register +/// +/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. +#[inline] +pub fn read() -> Apsr { + let bits: u32 = call_asm!(__apsr_r() -> u32); + Apsr { bits } +} diff --git a/src/rust/vendor/cortex-m/src/register/basepri.rs b/src/rust/vendor/cortex-m/src/register/basepri.rs new file mode 100644 index 000000000..07084cd26 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/basepri.rs @@ -0,0 +1,24 @@ +//! Base Priority Mask Register + +/// Reads the CPU register +#[inline] +pub fn read() -> u8 { + call_asm!(__basepri_r() -> u8) +} + +/// Writes to the CPU register +/// +/// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the +/// `cm7-r0p1` Cargo feature or this function WILL misbehave. +#[inline] +pub unsafe fn write(basepri: u8) { + #[cfg(feature = "cm7-r0p1")] + { + call_asm!(__basepri_w_cm7_r0p1(basepri: u8)); + } + + #[cfg(not(feature = "cm7-r0p1"))] + { + call_asm!(__basepri_w(basepri: u8)); + } +} diff --git a/src/rust/vendor/cortex-m/src/register/basepri_max.rs b/src/rust/vendor/cortex-m/src/register/basepri_max.rs new file mode 100644 index 000000000..cea38383d --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/basepri_max.rs @@ -0,0 +1,21 @@ +//! Base Priority Mask Register (conditional write) + +/// Writes to BASEPRI *if* +/// +/// - `basepri != 0` AND `basepri::read() == 0`, OR +/// - `basepri != 0` AND `basepri < basepri::read()` +/// +/// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the +/// `cm7-r0p1` Cargo feature or this function WILL misbehave. +#[inline] +pub fn write(basepri: u8) { + #[cfg(feature = "cm7-r0p1")] + { + call_asm!(__basepri_max_cm7_r0p1(basepri: u8)); + } + + #[cfg(not(feature = "cm7-r0p1"))] + { + call_asm!(__basepri_max(basepri: u8)); + } +} diff --git a/src/rust/vendor/cortex-m/src/register/control.rs b/src/rust/vendor/cortex-m/src/register/control.rs new file mode 100644 index 000000000..a991625b4 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/control.rs @@ -0,0 +1,164 @@ +//! Control register + +/// Control register +#[derive(Clone, Copy, Debug)] +pub struct Control { + bits: u32, +} + +impl Control { + /// Creates a `Control` value from raw bits. + #[inline] + pub fn from_bits(bits: u32) -> Self { + Self { bits } + } + + /// Returns the contents of the register as raw bits + #[inline] + pub fn bits(self) -> u32 { + self.bits + } + + /// Thread mode privilege level + #[inline] + pub fn npriv(self) -> Npriv { + if self.bits & (1 << 0) == (1 << 0) { + Npriv::Unprivileged + } else { + Npriv::Privileged + } + } + + /// Sets the thread mode privilege level value (nPRIV). + #[inline] + pub fn set_npriv(&mut self, npriv: Npriv) { + let mask = 1 << 0; + match npriv { + Npriv::Unprivileged => self.bits |= mask, + Npriv::Privileged => self.bits &= !mask, + } + } + + /// Currently active stack pointer + #[inline] + pub fn spsel(self) -> Spsel { + if self.bits & (1 << 1) == (1 << 1) { + Spsel::Psp + } else { + Spsel::Msp + } + } + + /// Sets the SPSEL value. + #[inline] + pub fn set_spsel(&mut self, spsel: Spsel) { + let mask = 1 << 1; + match spsel { + Spsel::Psp => self.bits |= mask, + Spsel::Msp => self.bits &= !mask, + } + } + + /// Whether context floating-point is currently active + #[inline] + pub fn fpca(self) -> Fpca { + if self.bits & (1 << 2) == (1 << 2) { + Fpca::Active + } else { + Fpca::NotActive + } + } + + /// Sets the FPCA value. + #[inline] + pub fn set_fpca(&mut self, fpca: Fpca) { + let mask = 1 << 2; + match fpca { + Fpca::Active => self.bits |= mask, + Fpca::NotActive => self.bits &= !mask, + } + } +} + +/// Thread mode privilege level +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Npriv { + /// Privileged + Privileged, + /// Unprivileged + Unprivileged, +} + +impl Npriv { + /// Is in privileged thread mode? + #[inline] + pub fn is_privileged(self) -> bool { + self == Npriv::Privileged + } + + /// Is in unprivileged thread mode? + #[inline] + pub fn is_unprivileged(self) -> bool { + self == Npriv::Unprivileged + } +} + +/// Currently active stack pointer +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Spsel { + /// MSP is the current stack pointer + Msp, + /// PSP is the current stack pointer + Psp, +} + +impl Spsel { + /// Is MSP the current stack pointer? + #[inline] + pub fn is_msp(self) -> bool { + self == Spsel::Msp + } + + /// Is PSP the current stack pointer? + #[inline] + pub fn is_psp(self) -> bool { + self == Spsel::Psp + } +} + +/// Whether context floating-point is currently active +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Fpca { + /// Floating-point context active. + Active, + /// No floating-point context active + NotActive, +} + +impl Fpca { + /// Is a floating-point context active? + #[inline] + pub fn is_active(self) -> bool { + self == Fpca::Active + } + + /// Is a floating-point context not active? + #[inline] + pub fn is_not_active(self) -> bool { + self == Fpca::NotActive + } +} + +/// Reads the CPU register +#[inline] +pub fn read() -> Control { + let bits: u32 = call_asm!(__control_r() -> u32); + Control { bits } +} + +/// Writes to the CPU register. +#[inline] +pub unsafe fn write(control: Control) { + let control = control.bits(); + call_asm!(__control_w(control: u32)); +} diff --git a/src/rust/vendor/cortex-m/src/register/faultmask.rs b/src/rust/vendor/cortex-m/src/register/faultmask.rs new file mode 100644 index 000000000..e57fa28df --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/faultmask.rs @@ -0,0 +1,35 @@ +//! Fault Mask Register + +/// All exceptions are ... +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Faultmask { + /// Active + Active, + /// Inactive, expect for NMI + Inactive, +} + +impl Faultmask { + /// All exceptions are active + #[inline] + pub fn is_active(self) -> bool { + self == Faultmask::Active + } + + /// All exceptions, except for NMI, are inactive + #[inline] + pub fn is_inactive(self) -> bool { + self == Faultmask::Inactive + } +} + +/// Reads the CPU register +#[inline] +pub fn read() -> Faultmask { + let r: u32 = call_asm!(__faultmask_r() -> u32); + if r & (1 << 0) == (1 << 0) { + Faultmask::Inactive + } else { + Faultmask::Active + } +} diff --git a/src/rust/vendor/cortex-m/src/register/fpscr.rs b/src/rust/vendor/cortex-m/src/register/fpscr.rs new file mode 100644 index 000000000..68692c732 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/fpscr.rs @@ -0,0 +1,305 @@ +//! Floating-point Status Control Register + +/// Floating-point Status Control Register +#[derive(Clone, Copy, Debug)] +pub struct Fpscr { + bits: u32, +} + +impl Fpscr { + /// Creates a `Fspcr` value from raw bits. + #[inline] + pub fn from_bits(bits: u32) -> Self { + Self { bits } + } + + /// Returns the contents of the register as raw bits + #[inline] + pub fn bits(self) -> u32 { + self.bits + } + + /// Read the Negative condition code flag + #[inline] + pub fn n(self) -> bool { + self.bits & (1 << 31) != 0 + } + + /// Sets the Negative condition code flag + #[inline] + pub fn set_n(&mut self, n: bool) { + let mask = 1 << 31; + match n { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Zero condition code flag + #[inline] + pub fn z(self) -> bool { + self.bits & (1 << 30) != 0 + } + + /// Sets the Zero condition code flag + #[inline] + pub fn set_z(&mut self, z: bool) { + let mask = 1 << 30; + match z { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Carry condition code flag + #[inline] + pub fn c(self) -> bool { + self.bits & (1 << 29) != 0 + } + + /// Sets the Carry condition code flag + #[inline] + pub fn set_c(&mut self, c: bool) { + let mask = 1 << 29; + match c { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Overflow condition code flag + #[inline] + pub fn v(self) -> bool { + self.bits & (1 << 28) != 0 + } + + /// Sets the Zero condition code flag + #[inline] + pub fn set_v(&mut self, v: bool) { + let mask = 1 << 28; + match v { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Alternative Half Precision bit + #[inline] + pub fn ahp(self) -> bool { + self.bits & (1 << 26) != 0 + } + + /// Sets the Alternative Half Precision bit + #[inline] + pub fn set_ahp(&mut self, ahp: bool) { + let mask = 1 << 26; + match ahp { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Default NaN mode bit + #[inline] + pub fn dn(self) -> bool { + self.bits & (1 << 25) != 0 + } + + /// Sets the Default NaN mode bit + #[inline] + pub fn set_dn(&mut self, dn: bool) { + let mask = 1 << 25; + match dn { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Flush to Zero mode bit + #[inline] + pub fn fz(self) -> bool { + self.bits & (1 << 24) != 0 + } + + /// Sets the Flush to Zero mode bit + #[inline] + pub fn set_fz(&mut self, fz: bool) { + let mask = 1 << 24; + match fz { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Rounding Mode control field + #[inline] + pub fn rmode(self) -> RMode { + match (self.bits & (3 << 22)) >> 22 { + 0 => RMode::Nearest, + 1 => RMode::PlusInfinity, + 2 => RMode::MinusInfinity, + _ => RMode::Zero, + } + } + + /// Sets the Rounding Mode control field + #[inline] + pub fn set_rmode(&mut self, rmode: RMode) { + let mask = 3 << 22; + match rmode { + RMode::Nearest => self.bits &= !mask, + RMode::PlusInfinity => self.bits = (self.bits & !mask) | (1 << 22), + RMode::MinusInfinity => self.bits = (self.bits & !mask) | (2 << 22), + RMode::Zero => self.bits |= mask, + } + } + + /// Read the Input Denormal cumulative exception bit + #[inline] + pub fn idc(self) -> bool { + self.bits & (1 << 7) != 0 + } + + /// Sets the Input Denormal cumulative exception bit + #[inline] + pub fn set_idc(&mut self, idc: bool) { + let mask = 1 << 7; + match idc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Inexact cumulative exception bit + #[inline] + pub fn ixc(self) -> bool { + self.bits & (1 << 4) != 0 + } + + /// Sets the Inexact cumulative exception bit + #[inline] + pub fn set_ixc(&mut self, ixc: bool) { + let mask = 1 << 4; + match ixc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Underflow cumulative exception bit + #[inline] + pub fn ufc(self) -> bool { + self.bits & (1 << 3) != 0 + } + + /// Sets the Underflow cumulative exception bit + #[inline] + pub fn set_ufc(&mut self, ufc: bool) { + let mask = 1 << 3; + match ufc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Overflow cumulative exception bit + #[inline] + pub fn ofc(self) -> bool { + self.bits & (1 << 2) != 0 + } + + /// Sets the Overflow cumulative exception bit + #[inline] + pub fn set_ofc(&mut self, ofc: bool) { + let mask = 1 << 2; + match ofc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Division by Zero cumulative exception bit + #[inline] + pub fn dzc(self) -> bool { + self.bits & (1 << 1) != 0 + } + + /// Sets the Division by Zero cumulative exception bit + #[inline] + pub fn set_dzc(&mut self, dzc: bool) { + let mask = 1 << 1; + match dzc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Invalid Operation cumulative exception bit + #[inline] + pub fn ioc(self) -> bool { + self.bits & (1 << 0) != 0 + } + + /// Sets the Invalid Operation cumulative exception bit + #[inline] + pub fn set_ioc(&mut self, ioc: bool) { + let mask = 1 << 0; + match ioc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } +} + +/// Rounding mode +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum RMode { + /// Round to Nearest (RN) mode. This is the reset value. + Nearest, + /// Round towards Plus Infinity (RP) mode. + PlusInfinity, + /// Round towards Minus Infinity (RM) mode. + MinusInfinity, + /// Round towards Zero (RZ) mode. + Zero, +} + +impl RMode { + /// Is Nearest the current rounding mode? + #[inline] + pub fn is_nearest(self) -> bool { + self == RMode::Nearest + } + + /// Is Plus Infinity the current rounding mode? + #[inline] + pub fn is_plus_infinity(self) -> bool { + self == RMode::PlusInfinity + } + + /// Is Minus Infinity the current rounding mode? + #[inline] + pub fn is_minus_infinity(self) -> bool { + self == RMode::MinusInfinity + } + + /// Is Zero the current rounding mode? + #[inline] + pub fn is_zero(self) -> bool { + self == RMode::Zero + } +} + +/// Read the FPSCR register +#[inline] +pub fn read() -> Fpscr { + let r: u32 = call_asm!(__fpscr_r() -> u32); + Fpscr::from_bits(r) +} + +/// Set the value of the FPSCR register +#[inline] +pub unsafe fn write(fpscr: Fpscr) { + let fpscr = fpscr.bits(); + call_asm!(__fpscr_w(fpscr: u32)); +} diff --git a/src/rust/vendor/cortex-m/src/register/lr.rs b/src/rust/vendor/cortex-m/src/register/lr.rs new file mode 100644 index 000000000..1aa546c8c --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/lr.rs @@ -0,0 +1,17 @@ +//! Link register + +/// Reads the CPU register +/// +/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. +#[inline] +pub fn read() -> u32 { + call_asm!(__lr_r() -> u32) +} + +/// Writes `bits` to the CPU register +/// +/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. +#[inline] +pub unsafe fn write(bits: u32) { + call_asm!(__lr_w(bits: u32)); +} diff --git a/src/rust/vendor/cortex-m/src/register/mod.rs b/src/rust/vendor/cortex-m/src/register/mod.rs new file mode 100644 index 000000000..48d157a50 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/mod.rs @@ -0,0 +1,68 @@ +//! Processor core registers +//! +//! The following registers can only be accessed in PRIVILEGED mode: +//! +//! - BASEPRI +//! - CONTROL +//! - FAULTMASK +//! - MSP +//! - PRIMASK +//! +//! The rest of registers (see list below) can be accessed in either, PRIVILEGED +//! or UNPRIVILEGED, mode. +//! +//! - APSR +//! - LR +//! - PC +//! - PSP +//! +//! The following registers are NOT available on ARMv6-M devices +//! (`thumbv6m-none-eabi`): +//! +//! - BASEPRI +//! - FAULTMASK +//! +//! The following registers are only available for devices with an FPU: +//! +//! - FPSCR +//! +//! # References +//! +//! - Cortex-M* Devices Generic User Guide - Section 2.1.3 Core registers + +#[cfg(all(not(armv6m), not(armv8m_base)))] +pub mod basepri; + +#[cfg(all(not(armv6m), not(armv8m_base)))] +pub mod basepri_max; + +pub mod control; + +#[cfg(all(not(armv6m), not(armv8m_base)))] +pub mod faultmask; + +#[cfg(has_fpu)] +pub mod fpscr; + +pub mod msp; + +pub mod primask; + +pub mod psp; + +#[cfg(armv8m_main)] +pub mod msplim; + +#[cfg(armv8m_main)] +pub mod psplim; + +// Accessing these registers requires inline assembly because their contents are tied to the current +// stack frame +#[cfg(feature = "inline-asm")] +pub mod apsr; + +#[cfg(feature = "inline-asm")] +pub mod lr; + +#[cfg(feature = "inline-asm")] +pub mod pc; diff --git a/src/rust/vendor/cortex-m/src/register/msp.rs b/src/rust/vendor/cortex-m/src/register/msp.rs new file mode 100644 index 000000000..bccc2ae82 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/msp.rs @@ -0,0 +1,32 @@ +//! Main Stack Pointer + +/// Reads the CPU register +#[inline] +pub fn read() -> u32 { + call_asm!(__msp_r() -> u32) +} + +/// Writes `bits` to the CPU register +#[inline] +#[deprecated = "calling this function invokes Undefined Behavior, consider asm::bootstrap as an alternative"] +pub unsafe fn write(bits: u32) { + call_asm!(__msp_w(bits: u32)); +} + +/// Reads the Non-Secure CPU register from Secure state. +/// +/// Executing this function in Non-Secure state will return zeroes. +#[cfg(armv8m)] +#[inline] +pub fn read_ns() -> u32 { + call_asm!(__msp_ns_r() -> u32) +} + +/// Writes `bits` to the Non-Secure CPU register from Secure state. +/// +/// Executing this function in Non-Secure state will be ignored. +#[cfg(armv8m)] +#[inline] +pub unsafe fn write_ns(bits: u32) { + call_asm!(__msp_ns_w(bits: u32)); +} diff --git a/src/rust/vendor/cortex-m/src/register/msplim.rs b/src/rust/vendor/cortex-m/src/register/msplim.rs new file mode 100644 index 000000000..ac6f9ed66 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/msplim.rs @@ -0,0 +1,13 @@ +//! Main Stack Pointer Limit Register + +/// Reads the CPU register +#[inline] +pub fn read() -> u32 { + call_asm!(__msplim_r() -> u32) +} + +/// Writes `bits` to the CPU register +#[inline] +pub unsafe fn write(bits: u32) { + call_asm!(__msplim_w(bits: u32)) +} diff --git a/src/rust/vendor/cortex-m/src/register/pc.rs b/src/rust/vendor/cortex-m/src/register/pc.rs new file mode 100644 index 000000000..0b33629ac --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/pc.rs @@ -0,0 +1,17 @@ +//! Program counter + +/// Reads the CPU register +/// +/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. +#[inline] +pub fn read() -> u32 { + call_asm!(__pc_r() -> u32) +} + +/// Writes `bits` to the CPU register +/// +/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. +#[inline] +pub unsafe fn write(bits: u32) { + call_asm!(__pc_w(bits: u32)); +} diff --git a/src/rust/vendor/cortex-m/src/register/primask.rs b/src/rust/vendor/cortex-m/src/register/primask.rs new file mode 100644 index 000000000..842ca49aa --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/primask.rs @@ -0,0 +1,35 @@ +//! Priority mask register + +/// All exceptions with configurable priority are ... +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Primask { + /// Active + Active, + /// Inactive + Inactive, +} + +impl Primask { + /// All exceptions with configurable priority are active + #[inline] + pub fn is_active(self) -> bool { + self == Primask::Active + } + + /// All exceptions with configurable priority are inactive + #[inline] + pub fn is_inactive(self) -> bool { + self == Primask::Inactive + } +} + +/// Reads the CPU register +#[inline] +pub fn read() -> Primask { + let r: u32 = call_asm!(__primask_r() -> u32); + if r & (1 << 0) == (1 << 0) { + Primask::Inactive + } else { + Primask::Active + } +} diff --git a/src/rust/vendor/cortex-m/src/register/psp.rs b/src/rust/vendor/cortex-m/src/register/psp.rs new file mode 100644 index 000000000..0bca22c3a --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/psp.rs @@ -0,0 +1,13 @@ +//! Process Stack Pointer + +/// Reads the CPU register +#[inline] +pub fn read() -> u32 { + call_asm!(__psp_r() -> u32) +} + +/// Writes `bits` to the CPU register +#[inline] +pub unsafe fn write(bits: u32) { + call_asm!(__psp_w(bits: u32)) +} diff --git a/src/rust/vendor/cortex-m/src/register/psplim.rs b/src/rust/vendor/cortex-m/src/register/psplim.rs new file mode 100644 index 000000000..8ee1e9455 --- /dev/null +++ b/src/rust/vendor/cortex-m/src/register/psplim.rs @@ -0,0 +1,13 @@ +//! Process Stack Pointer Limit Register + +/// Reads the CPU register +#[inline] +pub fn read() -> u32 { + call_asm!(__psplim_r() -> u32) +} + +/// Writes `bits` to the CPU register +#[inline] +pub unsafe fn write(bits: u32) { + call_asm!(__psplim_w(bits: u32)) +} diff --git a/src/rust/vendor/cortex-m/triagebot.toml b/src/rust/vendor/cortex-m/triagebot.toml new file mode 100644 index 000000000..fa0824ac5 --- /dev/null +++ b/src/rust/vendor/cortex-m/triagebot.toml @@ -0,0 +1 @@ +[assign] diff --git a/src/rust/vendor/critical-section/.cargo-checksum.json b/src/rust/vendor/critical-section/.cargo-checksum.json new file mode 100644 index 000000000..fdb1a2336 --- /dev/null +++ b/src/rust/vendor/critical-section/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"d77ec276b751670ca1d7618829f3f1cb8e8e79f06541137a35db4ba9835b4948","CODE_OF_CONDUCT.md":"8e25e95078b1a582086587adf8e1d907d43aacee6a072b8630d54a6289e5e0b9","Cargo.toml":"51883860e46bb12308427f26d0cb0e6a9ddbe83d2361a03569124c98a0c3e124","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"fee6bdac4b917351332567b9fd5013c2ef3c847dd113fd6216cf28e96637a157","README.md":"5e6c551ffe891fd5b9a3b6196d8961bbd5e92b1c764999d7e426a83fd23ac623","docs/msrv.md":"690a70e9ed6764198e4a5c0933a4124fc382091754d8bafb82241483ae2d89b9","src/lib.rs":"218ba6a5357feb9d03ffc1d695ffdad06dc09cc8d0e6b0435afb56e6bb0cd23e","src/mutex.rs":"f054732ff51654b7becd14861c7a27cb46ee469a9aaaf3ac8f48cb256bf321c0","src/std.rs":"5b90b71f092229af5131446736bbb50547f294577156fd87a1405ba7279f9136"},"package":"790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"} \ No newline at end of file diff --git a/src/rust/vendor/critical-section/CHANGELOG.md b/src/rust/vendor/critical-section/CHANGELOG.md new file mode 100644 index 000000000..319f4c1b2 --- /dev/null +++ b/src/rust/vendor/critical-section/CHANGELOG.md @@ -0,0 +1,149 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +No unreleased changes yet + +## [v1.2.0] - 2024-10-16 + +- Soundness fix: ensure the `CriticalSection` token is not `Send` or `Sync`, so that it can only be used in the thread that acquired it. [#55](https://github.com/rust-embedded/critical-section/issues/55) +- Soundness fix: Fix aliasing `&mut` in the `std` implementation. [#46](https://github.com/rust-embedded/critical-section/pull/46) +- Fix build with `restore-state-usize`. [#50](https://github.com/rust-embedded/critical-section/pull/50) + +## [v1.1.3] - 2024-08-22 + +- Added option to use a `usize` sized restore state + +## [v1.1.2] - 2023-08-09 + +- Clarified that `acquire()` must provide ordering guarantees +- Updated atomic-polyfill reference to point to portable-atomic instead +- Improved documentation for `Mutex` example +- Added list of some known implementations + +## [v1.1.1] - 2022-09-13 + +- On the `std` implementation, panicking inside the `critical_section::with()` closure no longer accidentally leaves the critical section locked (#26). + +## [v1.1.0] - 2022-08-17 + +- Added built-in critical section implementation using `std::sync::Mutex`, enabled by the `std` Cargo feature. +- MSRV changed to `1.54` when `std` feature is disabled, `1.63` when enabled. + +## [v1.0.0] - 2022-08-10 + +- Improved docs. + +## [v1.0.0-alpha.2] - 2022-07-28 + +- Change name of the `extern fn`s to avoid clash with critical-section 0.2. + +## [v1.0.0-alpha.1] - 2022-07-28 + +Breaking changes: + +- Removed all builtin impls. These are going to be provided by platform-support crates now. +- Renamed `custom_impl!` to `set_impl!`. +- RestoreState is now an opaque struct for the user, and a transparent `RawRestoreState` type alias for impl writers. +- RestoreState type is now configurable with Cargo features. Default is `()`. (previously it was fixed to `u8`.) +- Added own `CriticalSection` and `Mutex` types, instead of reexporting them from `bare_metal`. + +## [v0.2.8] - 2022-11-29 + +- Implemented critical-section by forwarding to version 1.1.1 + +Breaking changes: + +- `acquire` and `release` are only implemented if the restore-state used by + version 1.1.1 is an u8 or smaller. +- No default critical-section implementation is provided. + +Those breaking changes are necessary because versions <= 0.2.7 were unsound, and that +was impossible to fix without a breaking change. + +This version is meant to minimize that breaking change. However, all +users are encouraged to upgrade to critical-section 1.1. + +If you're seeing a linker error like `undefined symbol: _critical_section_1_0_acquire`, you're affected. To fix it: + +- If your target supports `std`: Add the `critical-section` dependency to `Cargo.toml` enabling the `std` feature. + + ```toml + [dependencies] + critical-section = { version = "1.1", features = ["std"]} + ``` + +- For single-core Cortex-M targets in privileged mode: + ```toml + [dependencies] + cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]} + ``` + +- For single-hart RISC-V targets in privileged mode: + ```toml + [dependencies] + riscv = { version = "0.10", features = ["critical-section-single-hart"]} + ``` + +- For other targets: check if your HAL or architecture-support crate has a `critical-section 1.0` implementation available. Otherwise, [provide your own](https://github.com/rust-embedded/critical-section#providing-an-implementation). + + +## [v0.2.7] - 2022-04-08 + +- Add support for AVR targets. + +## [v0.2.6] - 2022-04-02 + +- Improved docs. + +## [v0.2.5] - 2021-11-02 + +- Fix `std` implementation to allow reentrant (nested) critical sections. This would previously deadlock. + +## [v0.2.4] - 2021-09-24 + +- Add support for 32bit RISC-V targets. + +## [v0.2.3] - 2021-09-13 + +- Use correct `#[vcfg]` for `wasm` targets. + +## [v0.2.2] - 2021-09-13 + +- Added support for `wasm` targets. + +## [v0.2.1] - 2021-05-11 + +- Added critical section implementation for `std`, based on a global Mutex. + +## [v0.2.0] - 2021-05-10 + +- Breaking change: use `CriticalSection<'_>` instead of `&CriticalSection<'_>` + +## v0.1.0 - 2021-05-10 + +- First release + +[Unreleased]: https://github.com/rust-embedded/critical-section/compare/v1.2.0...HEAD +[v1.2.0]: https://github.com/rust-embedded/critical-section/compare/v1.1.3...v1.2.0 +[v1.1.3]: https://github.com/rust-embedded/critical-section/compare/v1.1.2...v1.1.3 +[v1.1.2]: https://github.com/rust-embedded/critical-section/compare/v1.1.1...v1.1.2 +[v1.1.1]: https://github.com/rust-embedded/critical-section/compare/v1.1.0...v1.1.1 +[v1.1.0]: https://github.com/rust-embedded/critical-section/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/rust-embedded/critical-section/compare/v1.0.0-alpha.2...v1.0.0 +[v1.0.0-alpha.2]: https://github.com/rust-embedded/critical-section/compare/v1.0.0-alpha.1...v1.0.0-alpha.2 +[v1.0.0-alpha.1]: https://github.com/rust-embedded/critical-section/compare/v0.2.7...v1.0.0-alpha.1 +[v0.2.8]: https://github.com/rust-embedded/critical-section/compare/v0.2.7...v0.2.8 +[v0.2.7]: https://github.com/rust-embedded/critical-section/compare/v0.2.6...v0.2.7 +[v0.2.6]: https://github.com/rust-embedded/critical-section/compare/v0.2.5...v0.2.6 +[v0.2.5]: https://github.com/rust-embedded/critical-section/compare/v0.2.4...v0.2.5 +[v0.2.4]: https://github.com/rust-embedded/critical-section/compare/v0.2.3...v0.2.4 +[v0.2.3]: https://github.com/rust-embedded/critical-section/compare/v0.2.2...v0.2.3 +[v0.2.2]: https://github.com/rust-embedded/critical-section/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-embedded/critical-section/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-embedded/critical-section/compare/v0.1.0...v0.2.0 diff --git a/src/rust/vendor/critical-section/CODE_OF_CONDUCT.md b/src/rust/vendor/critical-section/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..bcefc6a2a --- /dev/null +++ b/src/rust/vendor/critical-section/CODE_OF_CONDUCT.md @@ -0,0 +1,37 @@ +# The Rust Code of Conduct + +## Conduct + +**Contact**: [HAL team][team] + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [HAL team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[team]: https://github.com/rust-embedded/wg#the-hal-team diff --git a/src/rust/vendor/critical-section/Cargo.toml b/src/rust/vendor/critical-section/Cargo.toml new file mode 100644 index 000000000..e8413c1c9 --- /dev/null +++ b/src/rust/vendor/critical-section/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "critical-section" +version = "1.2.0" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Cross-platform critical section" +readme = "README.md" +categories = [ + "embedded", + "no-std", + "concurrency", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-embedded/critical-section" + +[lib] +name = "critical_section" +path = "src/lib.rs" + +[features] +restore-state-bool = [] +restore-state-none = [] +restore-state-u16 = [] +restore-state-u32 = [] +restore-state-u64 = [] +restore-state-u8 = [] +restore-state-usize = [] +std = ["restore-state-bool"] diff --git a/src/rust/vendor/critical-section/LICENSE-APACHE b/src/rust/vendor/critical-section/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/critical-section/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/critical-section/LICENSE-MIT b/src/rust/vendor/critical-section/LICENSE-MIT new file mode 100644 index 000000000..78bced90f --- /dev/null +++ b/src/rust/vendor/critical-section/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2022 The critical-section authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/critical-section/README.md b/src/rust/vendor/critical-section/README.md new file mode 100644 index 000000000..32f1678c0 --- /dev/null +++ b/src/rust/vendor/critical-section/README.md @@ -0,0 +1,250 @@ +# critical-section +[![crates.io](https://img.shields.io/crates/d/critical-section.svg)](https://crates.io/crates/critical-section) +[![crates.io](https://img.shields.io/crates/v/critical-section.svg)](https://crates.io/crates/critical-section) +[![Documentation](https://docs.rs/critical-section/badge.svg)](https://docs.rs/critical-section) + +This project is developed and maintained by the [HAL team][team]. + +A critical section that works everywhere! + +When writing software for embedded systems, it's common to use a "critical section" +as a basic primitive to control concurrency. A critical section is essentially a +mutex global to the whole process, that can be acquired by only one thread at a time. +This can be used to protect data behind mutexes, to [emulate atomics](https://crates.io/crates/portable-atomic) in +targets that don't support them, etc. + +There's a wide range of possible implementations depending on the execution environment: +- For bare-metal single core, disabling interrupts in the current (only) core. +- For bare-metal multicore, disabling interrupts in the current core and acquiring a hardware spinlock to prevent other cores from entering a critical section concurrently. +- For bare-metal using a RTOS, using library functions for acquiring a critical section, often named "scheduler lock" or "kernel lock". +- For bare-metal running in non-privileged mode, calling some system call is usually needed. +- For `std` targets, acquiring a global `std::sync::Mutex`. + +Libraries often need to use critical sections, but there's no universal API for this in `core`. This leads +library authors to hard-code them for their target, or at best add some `cfg`s to support a few targets. +This doesn't scale since there are many targets out there, and in the general case it's impossible to know +which critical section implementation is needed from the Rust target alone. For example, the `thumbv7em-none-eabi` target +could be cases 1-4 from the above list. + +This crate solves the problem by providing this missing universal API. + +- It provides functions `acquire`, `release` and `with` that libraries can directly use. +- It provides a way for any crate to supply an implementation. This allows "target support" crates such as architecture crates (`cortex-m`, `riscv`), RTOS bindings, or HALs for multicore chips to supply the correct implementation so that all the crates in the dependency tree automatically use it. + +## Usage in `no-std` binaries. + +First, add a dependency on a crate providing a critical section implementation. Enable the `critical-section-*` Cargo feature if required by the crate. + +Implementations are typically provided by either architecture-support crates, HAL crates, and OS/RTOS bindings, including: + +* The [`cortex-m`] crate provides an implementation for all single-core Cortex-M microcontrollers via its `critical-section-single-core` feature +* The [`riscv`] crate provides an implementation for all single-hart RISC-V microcontrollers via its `critical-section-single-hart` feature +* The [`msp430`] crate provides an implementation for all MSP430 microcontrollers via its `critical-section-single-core` feature +* The [`rp2040-hal`] crate provides a multi-core-safe critical section for the RP2040 microcontroller via its `critical-section-impl` feature +* The [`avr-device`] crate provides an implementation for all AVR microcontrollers via its `critical-section-impl` feature +* The [`esp-hal-common`] crate provides an implementation for ESP32 microcontrollers which is used by the ESP HALs +* The [`embassy-rp`] crate provides a multi-core-safe critical section for the RP2040 microcontroller via its `critical-section-impl` feature +* The [`nrf-softdevice`] crate provides a critical section that's compatible with the nRF soft-device firmware via its `critical-section-impl` feature + +[`cortex-m`]: https://crates.io/crates/cortex-m +[`riscv`]: https://crates.io/crates/riscv +[`msp430`]: https://crates.io/crates/msp430 +[`rp2040-hal`]: https://crates.io/crates/rp2040-hal +[`avr-device`]: https://crates.io/crates/avr-device +[`esp-hal-common`]: https://crates.io/crates/esp-hal-common +[`embassy-rp`]: https://docs.embassy.dev/embassy-rp +[`nrf-softdevice`]: https://docs.embassy.dev/nrf-softdevice + +For example, for single-core Cortex-M targets, you can use: + +```toml +[dependencies] +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]} +``` + +Then you can use `critical_section::with()`. + +```rust +use core::cell::Cell; +use critical_section::Mutex; + +static MY_VALUE: Mutex> = Mutex::new(Cell::new(0)); + +critical_section::with(|cs| { + // This code runs within a critical section. + + // `cs` is a token that you can use to "prove" that to some API, + // for example to a `Mutex`: + MY_VALUE.borrow(cs).set(42); +}); + +# #[cfg(not(feature = "std"))] // needed for `cargo test --features std` +# mod no_std { +# struct MyCriticalSection; +# critical_section::set_impl!(MyCriticalSection); +# unsafe impl critical_section::Impl for MyCriticalSection { +# unsafe fn acquire() -> () {} +# unsafe fn release(token: ()) {} +# } +# } +``` + +## Usage in `std` binaries. + +Add the `critical-section` dependency to `Cargo.toml` enabling the `std` feature. This makes the `critical-section` crate itself +provide an implementation based on `std::sync::Mutex`, so you don't have to add any other dependency. + +```toml +[dependencies] +critical-section = { version = "1.1", features = ["std"]} +``` + +## Usage in libraries + +If you're writing a library intended to be portable across many targets, simply add a dependency on `critical-section` +and use `critical_section::free` and/or `Mutex` as usual. + +**Do not** add any dependency supplying a critical section implementation. Do not enable any `critical-section-*` Cargo feature. +This has to be done by the end user, enabling the correct implementation for their target. + +**Do not** enable any Cargo feature in `critical-section`. + +## Usage in `std` tests for `no-std` libraries. + +If you want to run `std`-using tests in otherwise `no-std` libraries, enable the `std` feature in `dev-dependencies` only. +This way the main target will use the `no-std` implementation chosen by the end-user's binary, and only the test targets +will use the `std` implementation. + +```toml +[dependencies] +critical-section = "1.1" + +[dev-dependencies] +critical-section = { version = "1.1", features = ["std"]} +``` + +## Providing an implementation + +Crates adding support for a particular architecture, chip or operating system should provide a critical section implementation. +It is **strongly recommended** to gate the implementation behind a feature, so the user can still use another implementation +if needed (having two implementations in the same binary will cause linking to fail). + +Add the dependency, and a `critical-section-*` feature to your `Cargo.toml`: + +```toml +[features] +# Enable critical section implementation that does "foo" +critical-section-foo = ["critical-section/restore-state-bool"] + +[dependencies] +critical-section = { version = "1.0", optional = true } +``` + +Then, provide the critical implementation like this: + +```rust +# #[cfg(not(feature = "std"))] // needed for `cargo test --features std` +# mod no_std { +// This is a type alias for the enabled `restore-state-*` feature. +// For example, it is `bool` if you enable `restore-state-bool`. +use critical_section::RawRestoreState; + +struct MyCriticalSection; +critical_section::set_impl!(MyCriticalSection); + +unsafe impl critical_section::Impl for MyCriticalSection { + unsafe fn acquire() -> RawRestoreState { + // TODO + } + + unsafe fn release(token: RawRestoreState) { + // TODO + } +} +# } +``` + +## Troubleshooting + +### Undefined reference errors + +If you get an error like these: + +```not_rust +undefined reference to `_critical_section_1_0_acquire' +undefined reference to `_critical_section_1_0_release' +``` + +it is because you (or a library) are using `critical_section::with` without providing a critical section implementation. +Make sure you're depending on a crate providing the implementation, and have enabled the `critical-section-*` feature in it if required. See the `Usage` section above. + +The error can also be caused by having the dependency but never `use`ing it. This can be fixed by adding a dummy `use`: + +```rust,ignore +use the_cs_impl_crate as _; +``` + +### Duplicate symbol errors + +If you get errors like these: + +```not_rust +error: symbol `_critical_section_1_0_acquire` is already defined +``` + +it is because you have two crates trying to provide a critical section implementation. You can only +have one implementation in a program. + +You can use `cargo tree --format '{p} {f}'` to view all dependencies and their enabled features. Make sure +that in the whole dependency tree, exactly one implementation is provided. + +Check for multiple versions of the same crate as well. For example, check the `critical-section-single-core` +feature is not enabled for both `cortex-m` 0.7 and 0.8. + +## Why not generics? + +An alternative solution would be to use a `CriticalSection` trait, and make all +code that needs acquiring the critical section generic over it. This has a few problems: + +- It would require passing it as a generic param to a very big amount of code, which +would be quite unergonomic. +- It's common to put `Mutex`es in `static` variables, and `static`s can't +be generic. +- It would allow mixing different critical section implementations in the same program, +which would be unsound. + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on the following Rust versions: + +- If the `std` feature is not enabled: stable Rust 1.54 and up. +- If the `std` feature is enabled: stable Rust 1.63 and up. + +It might compile with older versions but that may change in any new patch release. + +See [here](docs/msrv.md) for details on how the MSRV may be upgraded. + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-hal-team diff --git a/src/rust/vendor/critical-section/docs/msrv.md b/src/rust/vendor/critical-section/docs/msrv.md new file mode 100644 index 000000000..ec0056a3a --- /dev/null +++ b/src/rust/vendor/critical-section/docs/msrv.md @@ -0,0 +1,30 @@ +# Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on all stable Rust versions going back to +the version stated as MSRV in the README. It *might* compile with even older versions but +that may change in any new patch release. + +## How the MSRV will be upgraded + +For `critical-section`, we do not consider upgrading the MSRV a strictly breaking change as defined by +[SemVer](https://semver.org). + +We follow these rules when upgrading it: + +- We will not update the MSRV on any patch release: \_.\_.*Z*. +- We may upgrade the MSRV on any *major* or *minor* release: *X*.*Y*.\_. +- We may upgrade the MSRV in any preliminary version release (e.g. an `-alpha` release) as + these serve as preparation for the final release. +- MSRV upgrades will be clearly stated in the changelog. + +This applies both to `0._._` releases as well as `>=1._._` releases. + +For example: + +For a given `x.y.z` release, we may upgrade the MSRV on `x` and `y` releases but not on `z` releases. + +If your MSRV upgrade policy differs from this, you are advised to specify the +`critical-section` dependency in your `Cargo.toml` accordingly. + +See the [Rust Embedded Working Group MSRV RFC](https://github.com/rust-embedded/wg/blob/master/rfcs/0523-msrv-2020.md) +for more background information and reasoning. diff --git a/src/rust/vendor/critical-section/src/lib.rs b/src/rust/vendor/critical-section/src/lib.rs new file mode 100644 index 000000000..3c05de83b --- /dev/null +++ b/src/rust/vendor/critical-section/src/lib.rs @@ -0,0 +1,308 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![doc = include_str!("../README.md")] + +mod mutex; +#[cfg(feature = "std")] +mod std; + +use core::marker::PhantomData; + +pub use self::mutex::Mutex; + +/// Critical section token. +/// +/// An instance of this type indicates that the current thread is executing code within a critical +/// section. +#[derive(Clone, Copy, Debug)] +pub struct CriticalSection<'cs> { + _private: PhantomData<&'cs ()>, + + // Prevent CriticalSection from being Send or Sync + // https://github.com/rust-embedded/critical-section/issues/55 + _not_send_sync: PhantomData<*mut ()>, +} + +impl<'cs> CriticalSection<'cs> { + /// Creates a critical section token. + /// + /// This method is meant to be used to create safe abstractions rather than being directly used + /// in applications. + /// + /// # Safety + /// + /// This must only be called when the current thread is in a critical section. The caller must + /// ensure that the returned instance will not live beyond the end of the critical section. + /// + /// The caller must use adequate fences to prevent the compiler from moving the + /// instructions inside the critical section to the outside of it. Sequentially consistent fences are + /// suggested immediately after entry and immediately before exit from the critical section. + /// + /// Note that the lifetime `'cs` of the returned instance is unconstrained. User code must not + /// be able to influence the lifetime picked for this type, since that might cause it to be + /// inferred to `'static`. + #[inline(always)] + pub unsafe fn new() -> Self { + CriticalSection { + _private: PhantomData, + _not_send_sync: PhantomData, + } + } +} + +#[cfg(any( + all(feature = "restore-state-none", feature = "restore-state-bool"), + all(feature = "restore-state-none", feature = "restore-state-u8"), + all(feature = "restore-state-none", feature = "restore-state-u16"), + all(feature = "restore-state-none", feature = "restore-state-u32"), + all(feature = "restore-state-none", feature = "restore-state-u64"), + all(feature = "restore-state-bool", feature = "restore-state-u8"), + all(feature = "restore-state-bool", feature = "restore-state-u16"), + all(feature = "restore-state-bool", feature = "restore-state-u32"), + all(feature = "restore-state-bool", feature = "restore-state-u64"), + all(feature = "restore-state-bool", feature = "restore-state-usize"), + all(feature = "restore-state-u8", feature = "restore-state-u16"), + all(feature = "restore-state-u8", feature = "restore-state-u32"), + all(feature = "restore-state-u8", feature = "restore-state-u64"), + all(feature = "restore-state-u8", feature = "restore-state-usize"), + all(feature = "restore-state-u16", feature = "restore-state-u32"), + all(feature = "restore-state-u16", feature = "restore-state-u64"), + all(feature = "restore-state-u16", feature = "restore-state-usize"), + all(feature = "restore-state-u32", feature = "restore-state-u64"), + all(feature = "restore-state-u32", feature = "restore-state-usize"), + all(feature = "restore-state-u64", feature = "restore-state-usize"), +))] +compile_error!("You must set at most one of these Cargo features: restore-state-none, restore-state-bool, restore-state-u8, restore-state-u16, restore-state-u32, restore-state-u64, restore-state-usize"); + +#[cfg(not(any( + feature = "restore-state-bool", + feature = "restore-state-u8", + feature = "restore-state-u16", + feature = "restore-state-u32", + feature = "restore-state-u64", + feature = "restore-state-usize" +)))] +type RawRestoreStateInner = (); + +#[cfg(feature = "restore-state-bool")] +type RawRestoreStateInner = bool; + +#[cfg(feature = "restore-state-u8")] +type RawRestoreStateInner = u8; + +#[cfg(feature = "restore-state-u16")] +type RawRestoreStateInner = u16; + +#[cfg(feature = "restore-state-u32")] +type RawRestoreStateInner = u32; + +#[cfg(feature = "restore-state-u64")] +type RawRestoreStateInner = u64; + +#[cfg(feature = "restore-state-usize")] +type RawRestoreStateInner = usize; + +// We have RawRestoreStateInner and RawRestoreState so that we don't have to copypaste the docs 5 times. +// In the docs this shows as `pub type RawRestoreState = u8` or whatever the selected type is, because +// the "inner" type alias is private. + +/// Raw, transparent "restore state". +/// +/// This type changes based on which Cargo feature is selected, out of +/// - `restore-state-none` (default, makes the type be `()`) +/// - `restore-state-bool` +/// - `restore-state-u8` +/// - `restore-state-u16` +/// - `restore-state-u32` +/// - `restore-state-u64` +/// - `restore-state-usize` +/// +/// See [`RestoreState`]. +/// +/// User code uses [`RestoreState`] opaquely, critical section implementations +/// use [`RawRestoreState`] so that they can use the inner value. +pub type RawRestoreState = RawRestoreStateInner; + +/// Opaque "restore state". +/// +/// Implementations use this to "carry over" information between acquiring and releasing +/// a critical section. For example, when nesting two critical sections of an +/// implementation that disables interrupts globally, acquiring the inner one won't disable +/// the interrupts since they're already disabled. The impl would use the restore state to "tell" +/// the corresponding release that it does *not* have to reenable interrupts yet, only the +/// outer release should do so. +/// +/// User code uses [`RestoreState`] opaquely, critical section implementations +/// use [`RawRestoreState`] so that they can use the inner value. +#[derive(Clone, Copy, Debug)] +pub struct RestoreState(RawRestoreState); + +impl RestoreState { + /// Create an invalid, dummy `RestoreState`. + /// + /// This can be useful to avoid `Option` when storing a `RestoreState` in a + /// struct field, or a `static`. + /// + /// Note that due to the safety contract of [`acquire`]/[`release`], you must not pass + /// a `RestoreState` obtained from this method to [`release`]. + pub const fn invalid() -> Self { + #[cfg(not(any( + feature = "restore-state-bool", + feature = "restore-state-u8", + feature = "restore-state-u16", + feature = "restore-state-u32", + feature = "restore-state-u64", + feature = "restore-state-usize" + )))] + return Self(()); + + #[cfg(feature = "restore-state-bool")] + return Self(false); + + #[cfg(feature = "restore-state-u8")] + return Self(0); + + #[cfg(feature = "restore-state-u16")] + return Self(0); + + #[cfg(feature = "restore-state-u32")] + return Self(0); + + #[cfg(feature = "restore-state-u64")] + return Self(0); + + #[cfg(feature = "restore-state-usize")] + return Self(0); + } +} + +/// Acquire a critical section in the current thread. +/// +/// This function is extremely low level. Strongly prefer using [`with`] instead. +/// +/// Nesting critical sections is allowed. The inner critical sections +/// are mostly no-ops since they're already protected by the outer one. +/// +/// # Safety +/// +/// - Each `acquire` call must be paired with exactly one `release` call in the same thread. +/// - `acquire` returns a "restore state" that you must pass to the corresponding `release` call. +/// - `acquire`/`release` pairs must be "properly nested", ie it's not OK to do `a=acquire(); b=acquire(); release(a); release(b);`. +/// - It is UB to call `release` if the critical section is not acquired in the current thread. +/// - It is UB to call `release` with a "restore state" that does not come from the corresponding `acquire` call. +/// - It must provide ordering guarantees at least equivalent to a [`core::sync::atomic::Ordering::Acquire`] +/// on a memory location shared by all critical sections, on which the `release` call will do a +/// [`core::sync::atomic::Ordering::Release`] operation. +#[inline(always)] +pub unsafe fn acquire() -> RestoreState { + extern "Rust" { + fn _critical_section_1_0_acquire() -> RawRestoreState; + } + + #[allow(clippy::unit_arg)] + RestoreState(_critical_section_1_0_acquire()) +} + +/// Release the critical section. +/// +/// This function is extremely low level. Strongly prefer using [`with`] instead. +/// +/// # Safety +/// +/// See [`acquire`] for the safety contract description. +#[inline(always)] +pub unsafe fn release(restore_state: RestoreState) { + extern "Rust" { + fn _critical_section_1_0_release(restore_state: RawRestoreState); + } + + #[allow(clippy::unit_arg)] + _critical_section_1_0_release(restore_state.0) +} + +/// Execute closure `f` in a critical section. +/// +/// Nesting critical sections is allowed. The inner critical sections +/// are mostly no-ops since they're already protected by the outer one. +/// +/// # Panics +/// +/// This function panics if the given closure `f` panics. In this case +/// the critical section is released before unwinding. +#[inline] +pub fn with(f: impl FnOnce(CriticalSection) -> R) -> R { + // Helper for making sure `release` is called even if `f` panics. + struct Guard { + state: RestoreState, + } + + impl Drop for Guard { + #[inline(always)] + fn drop(&mut self) { + unsafe { release(self.state) } + } + } + + let state = unsafe { acquire() }; + let _guard = Guard { state }; + + unsafe { f(CriticalSection::new()) } +} + +/// Methods required for a critical section implementation. +/// +/// This trait is not intended to be used except when implementing a critical section. +/// +/// # Safety +/// +/// Implementations must uphold the contract specified in [`crate::acquire`] and [`crate::release`]. +pub unsafe trait Impl { + /// Acquire the critical section. + /// + /// # Safety + /// + /// Callers must uphold the contract specified in [`crate::acquire`] and [`crate::release`]. + unsafe fn acquire() -> RawRestoreState; + + /// Release the critical section. + /// + /// # Safety + /// + /// Callers must uphold the contract specified in [`crate::acquire`] and [`crate::release`]. + unsafe fn release(restore_state: RawRestoreState); +} + +/// Set the critical section implementation. +/// +/// # Example +/// +/// ``` +/// # #[cfg(not(feature = "std"))] // needed for `cargo test --features std` +/// # mod no_std { +/// use critical_section::RawRestoreState; +/// +/// struct MyCriticalSection; +/// critical_section::set_impl!(MyCriticalSection); +/// +/// unsafe impl critical_section::Impl for MyCriticalSection { +/// unsafe fn acquire() -> RawRestoreState { +/// // ... +/// } +/// +/// unsafe fn release(restore_state: RawRestoreState) { +/// // ... +/// } +/// } +/// # } +#[macro_export] +macro_rules! set_impl { + ($t: ty) => { + #[no_mangle] + unsafe fn _critical_section_1_0_acquire() -> $crate::RawRestoreState { + <$t as $crate::Impl>::acquire() + } + #[no_mangle] + unsafe fn _critical_section_1_0_release(restore_state: $crate::RawRestoreState) { + <$t as $crate::Impl>::release(restore_state) + } + }; +} diff --git a/src/rust/vendor/critical-section/src/mutex.rs b/src/rust/vendor/critical-section/src/mutex.rs new file mode 100644 index 000000000..9f6088b57 --- /dev/null +++ b/src/rust/vendor/critical-section/src/mutex.rs @@ -0,0 +1,208 @@ +use super::CriticalSection; +use core::cell::{Ref, RefCell, RefMut, UnsafeCell}; + +/// A mutex based on critical sections. +/// +/// # Example +/// +/// ```no_run +/// # use critical_section::Mutex; +/// # use std::cell::Cell; +/// +/// static FOO: Mutex> = Mutex::new(Cell::new(42)); +/// +/// fn main() { +/// critical_section::with(|cs| { +/// FOO.borrow(cs).set(43); +/// }); +/// } +/// +/// fn interrupt_handler() { +/// let _x = critical_section::with(|cs| FOO.borrow(cs).get()); +/// } +/// ``` +/// +/// +/// # Design +/// +/// [`std::sync::Mutex`] has two purposes. It converts types that are [`Send`] +/// but not [`Sync`] into types that are both; and it provides +/// [interior mutability]. `critical_section::Mutex`, on the other hand, only adds +/// `Sync`. It does *not* provide interior mutability. +/// +/// This was a conscious design choice. It is possible to create multiple +/// [`CriticalSection`] tokens, either by nesting critical sections or `Copy`ing +/// an existing token. As a result, it would not be sound for [`Mutex::borrow`] +/// to return `&mut T`, because there would be nothing to prevent calling +/// `borrow` multiple times to create aliased `&mut T` references. +/// +/// The solution is to include a runtime check to ensure that each resource is +/// borrowed only once. This is what `std::sync::Mutex` does. However, this is +/// a runtime cost that may not be required in all circumstances. For instance, +/// `Mutex>` never needs to create `&mut T` or equivalent. +/// +/// If `&mut T` is needed, the simplest solution is to use `Mutex>`, +/// which is the closest analogy to `std::sync::Mutex`. [`RefCell`] inserts the +/// exact runtime check necessary to guarantee that the `&mut T` reference is +/// unique. +/// +/// To reduce verbosity when using `Mutex>`, we reimplement some of +/// `RefCell`'s methods on it directly. +/// +/// ```no_run +/// # use critical_section::Mutex; +/// # use std::cell::RefCell; +/// +/// static FOO: Mutex> = Mutex::new(RefCell::new(42)); +/// +/// fn main() { +/// critical_section::with(|cs| { +/// // Instead of calling this +/// let _ = FOO.borrow(cs).take(); +/// // Call this +/// let _ = FOO.take(cs); +/// // `RefCell::borrow` and `RefCell::borrow_mut` are renamed to +/// // `borrow_ref` and `borrow_ref_mut` to avoid name collisions +/// let _: &mut i32 = &mut *FOO.borrow_ref_mut(cs); +/// }) +/// } +/// ``` +/// +/// [`std::sync::Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html +/// [interior mutability]: https://doc.rust-lang.org/reference/interior-mutability.html +#[derive(Debug)] +pub struct Mutex { + // The `UnsafeCell` is not strictly necessary here: In theory, just using `T` should + // be fine. + // However, without `UnsafeCell`, the compiler may use niches inside `T`, and may + // read the niche value _without locking the mutex_. As we don't provide interior + // mutability, this is still not violating any aliasing rules and should be perfectly + // fine. But as the cost of adding `UnsafeCell` is very small, we add it out of + // cautiousness, just in case the reason `T` is not `Sync` in the first place is + // something very obscure we didn't consider. + inner: UnsafeCell, +} + +impl Mutex { + /// Creates a new mutex. + #[inline] + pub const fn new(value: T) -> Self { + Mutex { + inner: UnsafeCell::new(value), + } + } + + /// Gets a mutable reference to the contained value when the mutex is already uniquely borrowed. + /// + /// This does not require locking or a critical section since it takes `&mut self`, which + /// guarantees unique ownership already. Care must be taken when using this method to + /// **unsafely** access `static mut` variables, appropriate fences must be used to prevent + /// unwanted optimizations. + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.inner.get() } + } + + /// Unwraps the contained value, consuming the mutex. + #[inline] + pub fn into_inner(self) -> T { + self.inner.into_inner() + } + + /// Borrows the data for the duration of the critical section. + #[inline] + pub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T { + unsafe { &*self.inner.get() } + } +} + +impl Mutex> { + /// Borrow the data and call [`RefCell::replace`] + /// + /// This is equivalent to `self.borrow(cs).replace(t)` + /// + /// # Panics + /// + /// This call could panic. See the documentation for [`RefCell::replace`] + /// for more details. + #[inline] + #[track_caller] + pub fn replace<'cs>(&'cs self, cs: CriticalSection<'cs>, t: T) -> T { + self.borrow(cs).replace(t) + } + + /// Borrow the data and call [`RefCell::replace_with`] + /// + /// This is equivalent to `self.borrow(cs).replace_with(f)` + /// + /// # Panics + /// + /// This call could panic. See the documentation for + /// [`RefCell::replace_with`] for more details. + #[inline] + #[track_caller] + pub fn replace_with<'cs, F>(&'cs self, cs: CriticalSection<'cs>, f: F) -> T + where + F: FnOnce(&mut T) -> T, + { + self.borrow(cs).replace_with(f) + } + + /// Borrow the data and call [`RefCell::borrow`] + /// + /// This is equivalent to `self.borrow(cs).borrow()` + /// + /// # Panics + /// + /// This call could panic. See the documentation for [`RefCell::borrow`] + /// for more details. + #[inline] + #[track_caller] + pub fn borrow_ref<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, T> { + self.borrow(cs).borrow() + } + + /// Borrow the data and call [`RefCell::borrow_mut`] + /// + /// This is equivalent to `self.borrow(cs).borrow_mut()` + /// + /// # Panics + /// + /// This call could panic. See the documentation for [`RefCell::borrow_mut`] + /// for more details. + #[inline] + #[track_caller] + pub fn borrow_ref_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, T> { + self.borrow(cs).borrow_mut() + } +} + +impl Mutex> { + /// Borrow the data and call [`RefCell::take`] + /// + /// This is equivalent to `self.borrow(cs).take()` + /// + /// # Panics + /// + /// This call could panic. See the documentation for [`RefCell::take`] + /// for more details. + #[inline] + #[track_caller] + pub fn take<'cs>(&'cs self, cs: CriticalSection<'cs>) -> T { + self.borrow(cs).take() + } +} + +// NOTE A `Mutex` can be used as a channel so the protected data must be `Send` +// to prevent sending non-Sendable stuff (e.g. access tokens) across different +// threads. +unsafe impl Sync for Mutex where T: Send {} + +/// ``` compile_fail +/// fn bad(cs: critical_section::CriticalSection) -> &u32 { +/// let x = critical_section::Mutex::new(42u32); +/// x.borrow(cs) +/// } +/// ``` +#[cfg(doctest)] +const BorrowMustNotOutliveMutexTest: () = (); diff --git a/src/rust/vendor/critical-section/src/std.rs b/src/rust/vendor/critical-section/src/std.rs new file mode 100644 index 000000000..c86426f84 --- /dev/null +++ b/src/rust/vendor/critical-section/src/std.rs @@ -0,0 +1,87 @@ +use std::cell::Cell; +use std::mem::MaybeUninit; +use std::sync::{Mutex, MutexGuard}; + +static GLOBAL_MUTEX: Mutex<()> = Mutex::new(()); + +// This is initialized if a thread has acquired the CS, uninitialized otherwise. +static mut GLOBAL_GUARD: MaybeUninit> = MaybeUninit::uninit(); + +std::thread_local!(static IS_LOCKED: Cell = Cell::new(false)); + +struct StdCriticalSection; +crate::set_impl!(StdCriticalSection); + +unsafe impl crate::Impl for StdCriticalSection { + unsafe fn acquire() -> bool { + // Allow reentrancy by checking thread local state + IS_LOCKED.with(|l| { + if l.get() { + // CS already acquired in the current thread. + return true; + } + + // Note: it is fine to set this flag *before* acquiring the mutex because it's thread local. + // No other thread can see its value, there's no potential for races. + // This way, we hold the mutex for slightly less time. + l.set(true); + + // Not acquired in the current thread, acquire it. + let guard = match GLOBAL_MUTEX.lock() { + Ok(guard) => guard, + Err(err) => { + // Ignore poison on the global mutex in case a panic occurred + // while the mutex was held. + err.into_inner() + } + }; + GLOBAL_GUARD.write(guard); + + false + }) + } + + unsafe fn release(nested_cs: bool) { + if !nested_cs { + // SAFETY: As per the acquire/release safety contract, release can only be called + // if the critical section is acquired in the current thread, + // in which case we know the GLOBAL_GUARD is initialized. + // + // We have to `assume_init_read` then drop instead of `assume_init_drop` because: + // - drop requires exclusive access (&mut) to the contents + // - mutex guard drop first unlocks the mutex, then returns. In between those, there's a brief + // moment where the mutex is unlocked but a `&mut` to the contents exists. + // - During this moment, another thread can go and use GLOBAL_GUARD, causing `&mut` aliasing. + #[allow(let_underscore_lock)] + let _ = GLOBAL_GUARD.assume_init_read(); + + // Note: it is fine to clear this flag *after* releasing the mutex because it's thread local. + // No other thread can see its value, there's no potential for races. + // This way, we hold the mutex for slightly less time. + IS_LOCKED.with(|l| l.set(false)); + } + } +} + +#[cfg(test)] +mod tests { + use std::thread; + + use crate as critical_section; + + #[cfg(feature = "std")] + #[test] + #[should_panic(expected = "Not a PoisonError!")] + fn reusable_after_panic() { + let _ = thread::spawn(|| { + critical_section::with(|_| { + panic!("Boom!"); + }) + }) + .join(); + + critical_section::with(|_| { + panic!("Not a PoisonError!"); + }) + } +} diff --git a/src/rust/vendor/embedded-hal/.cargo-checksum.json b/src/rust/vendor/embedded-hal/.cargo-checksum.json new file mode 100644 index 000000000..34c6ce449 --- /dev/null +++ b/src/rust/vendor/embedded-hal/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"77ffedb0fed8fc0ca01187ff0e49ac5789de197cf9395873bcf8fe7dad4a07af","CODE_OF_CONDUCT.md":"8e25e95078b1a582086587adf8e1d907d43aacee6a072b8630d54a6289e5e0b9","Cargo.toml":"f38086e8578b2292f3c519060d723d6142e59930d72d12cdb1bbc5aaed09bf3c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"520bc4942f199aad3dfe939c475d67ffbddfea482e41fc4fcad8829b71affc99","README.md":"629413fa55785448460269d379312aed6618869606a1c761d86aad32eb76c2cc","src/adc.rs":"bfa0ae49cef222ec2b04178ce1d6dc8db4fbc8acebf1a82657de4b1447ecf313","src/blocking/can.rs":"4db197e3f8d77967a7bac0beca9605063a1c6abbc5cc03d9b74fc09fbf36ba42","src/blocking/delay.rs":"a483acfe72b033f8e18273bf744c237a8de803cbbaf820aeb2ce32458ac3b684","src/blocking/i2c.rs":"966589f5f9d3102bb1e88150a503967b51cd81dda7527c803c03a10e4aa2ffa8","src/blocking/mod.rs":"02bbd31f9e68bb7fa10977c6934b9ae046138fbd6f5ebe6c5dfac6fa3332a63a","src/blocking/rng.rs":"eed57d8770235cc2454452fd5b86948a2143bdb5220b0e14fc36003f4223b7c9","src/blocking/serial.rs":"1587824b545e6e781efafc8720f1a3c19f0e9a7cab3ad0cd96cc99f5e84f8667","src/blocking/spi.rs":"ddb233a3bcf8a20b8da0d95c0cb2bdcbefd729a93b8a568a879680b026e00e19","src/can/id.rs":"691582de769af2c893cdceab783ad0b28b984de7466c419cbe17efd9f60f2e51","src/can/mod.rs":"b82b04a537415180918c2de36af9f5d7e8ecc76091bec5fc6f7208a14bfaae89","src/can/nb.rs":"6c4325d38b6aebbaa7293286482ab9645337b8236e054bed8835456f2aa32019","src/digital/mod.rs":"08f5144d2bcf8d4cdde1995b3617f5da14309926f66f4e9568100d7794da1b91","src/digital/v1.rs":"afd83c7e86c4957adf682e2280f7ac14a94dc8cdd43d70cc8890c2d8cf06be51","src/digital/v1_compat.rs":"192ec293c4e7f6bfbf9f65f3b3b1e2b47190761cc9e2e5ea230e0d5e7d69d4f3","src/digital/v2.rs":"89fa6a89cdbbb68f498fb7a2d87842b5b4391a978c7205ff1a0479983223c9f9","src/digital/v2_compat.rs":"bae546f4583eeedafa3e5c7e93f8fa5a56716e05a0ff3f5cc5aaf4a461e17adf","src/fmt.rs":"e0e657a52545f5099f2f0d49625b1448d1d566ece2c5badd8611e40f4afd7aba","src/lib.rs":"f9abd6a03322386af8099bc790bf247ab246351e965d6fab9650f433ec2f6584","src/prelude.rs":"d72d971fa63105e0ef6a0278fdecd4eb97f7fc47520455575c3165ef33ddb29d","src/serial.rs":"73f2e98712e12cc06ffd47d4c797ef8709ff56ebbad0db2e726aea1bf2ae383b","src/spi.rs":"f925b243fd86d7768a63605e8d3f035174be25df002c4abeedf4cd4c00b91594","src/timer.rs":"6c8e09a566375cfa90f7dd619544e84205dcaba8a87afa61ee447d57104b78ad","src/watchdog.rs":"e507438a87ee8a2a4162f717cc0472deecc8a29385b15a2c8ecc44e602d96e9a"},"package":"35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"} \ No newline at end of file diff --git a/src/rust/vendor/embedded-hal/CHANGELOG.md b/src/rust/vendor/embedded-hal/CHANGELOG.md new file mode 100644 index 000000000..7fc2bbecc --- /dev/null +++ b/src/rust/vendor/embedded-hal/CHANGELOG.md @@ -0,0 +1,143 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.2.7] - 2022-02-09 + +### Added + +- Backport CAN interface from the upcoming 1.0 release. + +## [v0.2.6] - 2021-08-03 + +### Added + +Backported non-breaking changes from the upcoming 1.0 release: + +- `Transactional` SPI interface for executing groups of SPI transactions. +- `Transactional` I2C interface for executing groups of I2C transactions. +- 10-bit addressing mode for I2C traits. +- `set_state` method for `OutputPin` using an input `PinState` value. +- `IoPin` trait for pins that can change between being inputs or outputs + dynamically. + + +## [v0.2.5] - 2021-04-28 + +### Changed + +- Updated `nb` dependency to version `0.1.3` to ensure compatibility with `nb` version `1.0`. + + +## [v0.2.4] - 2020-06-17 + +### Changed + +- Fix for `dyn` traits in fmt.rs +- Remove `#![deny(warnings)]`, now imposed y CI +- Updates stm32f30x from 0.6.0 to 0.8.0 +- Fix the input pin v2->v1 compatibility shim constructor, where `OldInputPin::new` + was incorrectly implemented for `v1::OutputPin` values. + + +## [v0.2.3] - 2019-05-09 + +### Added +- A new version of the digital `OutputPin`, `StatefulOutputPin`, `ToggleableOutputPin` + and `InputPin` traits has been added under `digital::v2`. These traits are now + fallible and their methods now return a `Result` type as setting an output pin + and reading an input pin could potentially fail. + See [here](https://github.com/rust-embedded/embedded-hal/issues/95) for more info. +- Compatibility shims between `digital::v1` and `digital::v2` traits allowing v1 traits + to be implicitly promoted to v2, and for v2 traits to be explicitly cast to v1 wrappers. + +### Changed +- The current versions of the `OutputPin`, `StatefulOutputPin`, `ToggleableOutputPin` + and `InputPin` traits have been marked as deprecated. Please use the new versions + included in `digital::v2`. + See [here](https://github.com/rust-embedded/embedded-hal/issues/95) for more info. + + +## [v0.2.2] - 2018-11-03 + +### Added + +- Added the Rust Code of Conduct to this repository +- The first ADC-related trait. This is a simple trait for one-shot conversions. +- Iterator-based blocking write and write+read traits have been added to I2C and SPI. +- New helper constants for SPI modes. +- A new trait for a cancellable countdown. +- New traits for watchdog timer management, including startup, feeding, and stopping. + +### Changed +- Updated docs to clarify I2C address bit widths and expectations. + + +## [v0.2.1] - 2018-05-14 + +### Changed + +- Auto-generated documentation (docs.rs) now includes the unproven traits. + +## [v0.2.0] - 2018-05-12 + +### Added + +- A `ToggeableOutputPin` trait has been added. This trait contains a single method: `toggle` that + can be used to toggle the state of a push-pull pin. + +### Changed + +- [breaking-change] The signature of `CountDown.wait` changed; it now returns `nb::Result<(), + Void>`. Where [`Void`] is the stable alternative to the never type, `!`, provided by the stable + [`void`] crate. Implementations of the `CountDown` trait will have to be updated to use the new + signature. With this change this crate compiles on the stable and beta channels. + +[`Void`]: https://docs.rs/void/1.0.2/void/enum.Void.html +[`void`]: https://crates.io/crates/void + +- [breaking-change] the `OutputPin.is_{low,high}` methods have been moved into its own trait + `StatefulOutputPin` and renamed to `is_set_{low,high}`. + +- It has been clarified in the documentation that `OutputPin` must be implemented for push-pull + output pins (and e.g. not for open drain output pins). + +## [v0.1.3] - 2018-05-14 + +### Changed + +- Re-export most / unchanged traits from embedded-hal v0.2.x to allow inter-operation between HAL + implementations and drivers that are using different minor versions. + +## [v0.1.2] - 2018-02-14 + +### Added + +- Unproven `blocking::serial::*` traits + +## [v0.1.1] - 2018-02-06 + +### Added + +- Unproven `digital::InputPin` trait + +## v0.1.0 - 2018-01-16 + +Initial release + +[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.7...v0.2.x +[v0.2.7]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.6...v0.2.7 +[v0.2.6]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.5...v0.2.6 +[v0.2.5]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.4...v0.2.5 +[v0.2.4]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.3...v0.2.4 +[v0.2.3]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.2...v0.2.3 +[v0.2.2]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-embedded/embedded-hal/compare/v0.1.2...v0.2.0 +[v0.1.2]: https://github.com/rust-embedded/embedded-hal/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-embedded/embedded-hal/compare/v0.1.0...v0.1.1 diff --git a/src/rust/vendor/embedded-hal/CODE_OF_CONDUCT.md b/src/rust/vendor/embedded-hal/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..bcefc6a2a --- /dev/null +++ b/src/rust/vendor/embedded-hal/CODE_OF_CONDUCT.md @@ -0,0 +1,37 @@ +# The Rust Code of Conduct + +## Conduct + +**Contact**: [HAL team][team] + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [HAL team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[team]: https://github.com/rust-embedded/wg#the-hal-team diff --git a/src/rust/vendor/embedded-hal/Cargo.toml b/src/rust/vendor/embedded-hal/Cargo.toml new file mode 100644 index 000000000..94c694882 --- /dev/null +++ b/src/rust/vendor/embedded-hal/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "embedded-hal" +version = "0.2.7" +authors = ["The Embedded HAL Team ", "Jorge Aparicio ", "Jonathan 'theJPster' Pallant "] +description = " A Hardware Abstraction Layer (HAL) for embedded systems " +documentation = "https://docs.rs/embedded-hal" +readme = "README.md" +keywords = ["hal", "IO"] +categories = ["asynchronous", "embedded", "hardware-support", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-embedded/embedded-hal" +[package.metadata.docs.rs] +features = ["unproven"] +[dependencies.nb] +version = "0.1.3" + +[dependencies.void] +version = "1.0.2" +default-features = false +[dev-dependencies.futures] +version = "0.1.17" + +[dev-dependencies.stm32f30x] +version = "0.8.0" + +[features] +unproven = ["nb/unstable"] diff --git a/src/rust/vendor/embedded-hal/LICENSE-APACHE b/src/rust/vendor/embedded-hal/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/embedded-hal/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/embedded-hal/LICENSE-MIT b/src/rust/vendor/embedded-hal/LICENSE-MIT new file mode 100644 index 000000000..52cb453f2 --- /dev/null +++ b/src/rust/vendor/embedded-hal/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017-2018 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/embedded-hal/README.md b/src/rust/vendor/embedded-hal/README.md new file mode 100644 index 000000000..66d9a33b8 --- /dev/null +++ b/src/rust/vendor/embedded-hal/README.md @@ -0,0 +1,86 @@ +# `embedded-hal` + +> A Hardware Abstraction Layer (HAL) for embedded systems + +This project is developed and maintained by the [HAL team][team]. + +## [API reference] + +[API reference]: https://docs.rs/embedded-hal + +## How-to: add a new trait + +This is the suggested approach to adding a new trait to `embedded-hal` + +### Discussion + +Ideally, before proposing a new trait, or set of traits, you should create an issue where the use +cases and requirements of the trait(s) are discussed. + +These issues will be labeled as `discussion`s in the issue tracker. + +### Proposing a trait + +Once there's consensus on the requirements of the trait(s) a new issue, or a PR, with a proposal +should be opened. The proposal should include the actual trait definitions as well as a link to the +issue with previous discussion, if there was one. + +If the proposal includes more than one alternative then there should be further discussion to try to +single out the best alternative. + +These issues / PRs will be labeled as `proposal`s in the issue tracker. + +### Testing period + +If there are no objections to the proposal the new trait(s) will land behind the "unproven" Cargo +feature and an issue about the new trait(s) will be created. If the proposal includes several +alternatives and a single one couldn't be chosen as the best then each alternative will land behind +a different Cargo feature, e.g. "alt1" or "alt2". + +The traits will undergo a testing period before they move into the set of proven traits. During +this period users are encouraged to try to implement the unproven traits for their platforms and to +build drivers on top of them. Problems implementing the trait(s) as well as successful +implementations should be reported on the corresponding issue. + +To leave the unproven state at least *two* implementations of the trait(s) for different platforms +(ideally, the two platforms should be from different vendors) and *one* generic driver built on top +of the trait(s), or alternatively one demo program that exercises the trait (via generic function / +trait object), *should* be demonstrated. If, instead, reports indicate that the proposed trait(s) +can't be implemented for a certain platform then the trait(s) will be removed and we'll go back to +the drawing board. + +Issues used to track unproven APIs will be labeled as `unproven-api`s in the issue tracker and they +may also include the labels `needs-impl` and `needs-driver` to signal what's required for them to +move to the set of proven traits. + +## Implementations and drivers + +For a list of `embedded-hal` implementations and driver crates check the [awesome-embedded-rust] +list. + +[awesome-embedded-rust]: https://github.com/rust-embedded/awesome-embedded-rust#driver-crates + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-hal-team diff --git a/src/rust/vendor/embedded-hal/src/adc.rs b/src/rust/vendor/embedded-hal/src/adc.rs new file mode 100644 index 000000000..cb7d7363f --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/adc.rs @@ -0,0 +1,98 @@ +//! Analog-digital conversion traits + +#[cfg(feature = "unproven")] +use nb; + +/// A marker trait to identify MCU pins that can be used as inputs to an ADC channel. +/// +/// This marker trait denotes an object, i.e. a GPIO pin, that is ready for use as an input to the +/// ADC. As ADCs channels can be supplied by multiple pins, this trait defines the relationship +/// between the physical interface and the ADC sampling buffer. +/// +/// ``` +/// # use std::marker::PhantomData; +/// # use embedded_hal::adc::Channel; +/// +/// struct Adc1; // Example ADC with single bank of 8 channels +/// struct Gpio1Pin1(PhantomData); +/// struct Analog(()); // marker type to denote a pin in "analog" mode +/// +/// // GPIO 1 pin 1 can supply an ADC channel when it is configured in Analog mode +/// impl Channel for Gpio1Pin1 { +/// type ID = u8; // ADC channels are identified numerically +/// +/// fn channel() -> u8 { 7_u8 } // GPIO pin 1 is connected to ADC channel 7 +/// } +/// +/// struct Adc2; // ADC with two banks of 16 channels +/// struct Gpio2PinA(PhantomData); +/// struct AltFun(()); // marker type to denote some alternate function mode for the pin +/// +/// // GPIO 2 pin A can supply an ADC channel when it's configured in some alternate function mode +/// impl Channel for Gpio2PinA { +/// type ID = (u8, u8); // ADC channels are identified by bank number and channel number +/// +/// fn channel() -> (u8, u8) { (0, 3) } // bank 0 channel 3 +/// } +/// ``` +#[cfg(feature = "unproven")] +pub trait Channel { + /// Channel ID type + /// + /// A type used to identify this ADC channel. For example, if the ADC has eight channels, this + /// might be a `u8`. If the ADC has multiple banks of channels, it could be a tuple, like + /// `(u8: bank_id, u8: channel_id)`. + type ID; + + /// Get the specific ID that identifies this channel, for example `0_u8` for the first ADC + /// channel, if Self::ID is u8. + fn channel() -> Self::ID; + + // `channel` is a function due to [this reported + // issue](https://github.com/rust-lang/rust/issues/54973). Something about blanket impls + // combined with `type ID; const CHANNEL: Self::ID;` causes problems. + //const CHANNEL: Self::ID; +} + +/// ADCs that sample on single channels per request, and do so at the time of the request. +/// +/// This trait is the interface to an ADC that is configured to read a specific channel at the time +/// of the request (in contrast to continuous asynchronous sampling). +/// +/// ``` +/// use embedded_hal::adc::{Channel, OneShot}; +/// +/// struct MyAdc; // 10-bit ADC, with 5 channels +/// # impl MyAdc { +/// # pub fn power_up(&mut self) {} +/// # pub fn power_down(&mut self) {} +/// # pub fn do_conversion(&mut self, chan: u8) -> u16 { 0xAA55_u16 } +/// # } +/// +/// impl OneShot for MyAdc +/// where +/// WORD: From, +/// PIN: Channel, +/// { +/// type Error = (); +/// +/// fn read(&mut self, _pin: &mut PIN) -> nb::Result { +/// let chan = 1 << PIN::channel(); +/// self.power_up(); +/// let result = self.do_conversion(chan); +/// self.power_down(); +/// Ok(result.into()) +/// } +/// } +/// ``` +#[cfg(feature = "unproven")] +pub trait OneShot> { + /// Error type returned by ADC methods + type Error; + + /// Request that the ADC begin a conversion on the specified pin + /// + /// This method takes a `Pin` reference, as it is expected that the ADC will be able to sample + /// whatever channel underlies the pin. + fn read(&mut self, pin: &mut Pin) -> nb::Result; +} diff --git a/src/rust/vendor/embedded-hal/src/blocking/can.rs b/src/rust/vendor/embedded-hal/src/blocking/can.rs new file mode 100644 index 000000000..b13885abe --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/blocking/can.rs @@ -0,0 +1,17 @@ +//! Blocking CAN API + +/// A blocking CAN interface that is able to transmit and receive frames. +pub trait Can { + /// Associated frame type. + type Frame: crate::can::Frame; + + /// Associated error type. + type Error: crate::can::Error; + + /// Puts a frame in the transmit buffer. Blocks until space is available in + /// the transmit buffer. + fn transmit(&mut self, frame: &Self::Frame) -> Result<(), Self::Error>; + + /// Blocks until a frame was received or an error occured. + fn receive(&mut self) -> Result; +} diff --git a/src/rust/vendor/embedded-hal/src/blocking/delay.rs b/src/rust/vendor/embedded-hal/src/blocking/delay.rs new file mode 100644 index 000000000..177c29ccd --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/blocking/delay.rs @@ -0,0 +1,26 @@ +//! Delays +//! +//! # What's the difference between these traits and the `timer::CountDown` trait? +//! +//! The `Timer` trait provides a *non-blocking* timer abstraction and it's meant to be used to build +//! higher level abstractions like I/O operations with timeouts. OTOH, these delays traits only +//! provide *blocking* functionality. Note that you can also use the `timer::CountDown` trait to +//! implement blocking delays. + +/// Millisecond delay +/// +/// `UXX` denotes the range type of the delay time. `UXX` can be `u8`, `u16`, etc. A single type can +/// implement this trait for different types of `UXX`. +pub trait DelayMs { + /// Pauses execution for `ms` milliseconds + fn delay_ms(&mut self, ms: UXX); +} + +/// Microsecond delay +/// +/// `UXX` denotes the range type of the delay time. `UXX` can be `u8`, `u16`, etc. A single type can +/// implement this trait for different types of `UXX`. +pub trait DelayUs { + /// Pauses execution for `us` microseconds + fn delay_us(&mut self, us: UXX); +} diff --git a/src/rust/vendor/embedded-hal/src/blocking/i2c.rs b/src/rust/vendor/embedded-hal/src/blocking/i2c.rs new file mode 100644 index 000000000..60bb1538d --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/blocking/i2c.rs @@ -0,0 +1,297 @@ +//! Blocking I2C API +//! +//! This API supports 7-bit and 10-bit addresses. Traits feature an `AddressMode` +//! marker type parameter. Two implementation of the `AddressMode` exist: +//! `SevenBitAddress` and `TenBitAddress`. +//! +//! Through this marker types it is possible to implement each address mode for +//! the traits independently in `embedded-hal` implementations and device drivers +//! can depend only on the mode that they support. +//! +//! Additionally, the I2C 10-bit address mode has been developed to be fully +//! backwards compatible with the 7-bit address mode. This allows for a +//! software-emulated 10-bit addressing implementation if the address mode +//! is not supported by the hardware. +//! +//! Since 7-bit addressing is the mode of the majority of I2C devices, +//! `SevenBitAddress` has been set as default mode and thus can be omitted if desired. +//! +//! ## Examples +//! +//! ### `embedded-hal` implementation for an MCU +//! Here is an example of an embedded-hal implementation of the `Write` trait +//! for both modes: +//! ``` +//! # use embedded_hal::blocking::i2c::{SevenBitAddress, TenBitAddress, Write}; +//! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing. +//! pub struct I2c0; +//! +//! impl Write for I2c0 +//! { +//! # type Error = (); +//! # +//! fn write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! } +//! +//! impl Write for I2c0 +//! { +//! # type Error = (); +//! # +//! fn write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! } +//! ``` +//! +//! ### Device driver compatible only with 7-bit addresses +//! +//! For demonstration purposes the address mode parameter has been omitted in this example. +//! +//! ``` +//! # use embedded_hal::blocking::i2c::WriteRead; +//! const ADDR: u8 = 0x15; +//! # const TEMP_REGISTER: u8 = 0x1; +//! pub struct TemperatureSensorDriver { +//! i2c: I2C, +//! } +//! +//! impl TemperatureSensorDriver +//! where +//! I2C: WriteRead, +//! { +//! pub fn read_temperature(&mut self) -> Result { +//! let mut temp = [0]; +//! self.i2c +//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .and(Ok(temp[0])) +//! } +//! } +//! ``` +//! +//! ### Device driver compatible only with 10-bit addresses +//! +//! ``` +//! # use embedded_hal::blocking::i2c::{TenBitAddress, WriteRead}; +//! const ADDR: u16 = 0x158; +//! # const TEMP_REGISTER: u8 = 0x1; +//! pub struct TemperatureSensorDriver { +//! i2c: I2C, +//! } +//! +//! impl TemperatureSensorDriver +//! where +//! I2C: WriteRead, +//! { +//! pub fn read_temperature(&mut self) -> Result { +//! let mut temp = [0]; +//! self.i2c +//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .and(Ok(temp[0])) +//! } +//! } +//! ``` + +use crate::private; + +impl private::Sealed for SevenBitAddress {} +impl private::Sealed for TenBitAddress {} + +/// Address mode (7-bit / 10-bit) +/// +/// Note: This trait is sealed and should not be implemented outside of this crate. +pub trait AddressMode: private::Sealed {} + +/// 7-bit address mode type +pub type SevenBitAddress = u8; + +/// 10-bit address mode type +pub type TenBitAddress = u16; + +impl AddressMode for SevenBitAddress {} + +impl AddressMode for TenBitAddress {} + +/// Blocking read +pub trait Read { + /// Error type + type Error; + + /// Reads enough bytes from slave with `address` to fill `buffer` + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+R MAK MAK ... NMAK SP + /// Slave: SAK B0 B1 ... BN + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+R` = slave address followed by bit 1 to indicate reading + /// - `SAK` = slave acknowledge + /// - `Bi` = ith byte of data + /// - `MAK` = master acknowledge + /// - `NMAK` = master no acknowledge + /// - `SP` = stop condition + fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error>; +} + +/// Blocking write +pub trait Write { + /// Error type + type Error; + + /// Writes bytes to slave with address `address` + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+W B0 B1 ... BN SP + /// Slave: SAK SAK SAK ... SAK + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+W` = slave address followed by bit 0 to indicate writing + /// - `SAK` = slave acknowledge + /// - `Bi` = ith byte of data + /// - `SP` = stop condition + fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error>; +} + +/// Blocking write (iterator version) +pub trait WriteIter { + /// Error type + type Error; + + /// Writes bytes to slave with address `address` + /// + /// # I2C Events (contract) + /// + /// Same as `Write` + fn write(&mut self, address: A, bytes: B) -> Result<(), Self::Error> + where + B: IntoIterator; +} + +/// Blocking write + read +pub trait WriteRead { + /// Error type + type Error; + + /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a + /// single transaction* + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP + /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+W` = slave address followed by bit 0 to indicate writing + /// - `SAK` = slave acknowledge + /// - `Oi` = ith outgoing byte of data + /// - `SR` = repeated start condition + /// - `SAD+R` = slave address followed by bit 1 to indicate reading + /// - `Ii` = ith incoming byte of data + /// - `MAK` = master acknowledge + /// - `NMAK` = master no acknowledge + /// - `SP` = stop condition + fn write_read( + &mut self, + address: A, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error>; +} + +/// Blocking write (iterator version) + read +pub trait WriteIterRead { + /// Error type + type Error; + + /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a + /// single transaction* + /// + /// # I2C Events (contract) + /// + /// Same as the `WriteRead` trait + fn write_iter_read( + &mut self, + address: A, + bytes: B, + buffer: &mut [u8], + ) -> Result<(), Self::Error> + where + B: IntoIterator; +} + +/// Transactional I2C operation. +/// +/// Several operations can be combined as part of a transaction. +#[derive(Debug, PartialEq)] +pub enum Operation<'a> { + /// Read data into the provided buffer + Read(&'a mut [u8]), + /// Write data from the provided buffer + Write(&'a [u8]), +} + +/// Transactional I2C interface. +/// +/// This allows combining operations within an I2C transaction. +pub trait Transactional { + /// Error type + type Error; + + /// Execute the provided operations on the I2C bus. + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + fn exec<'a>(&mut self, address: A, operations: &mut [Operation<'a>]) + -> Result<(), Self::Error>; +} + +/// Transactional I2C interface (iterator version). +/// +/// This allows combining operation within an I2C transaction. +pub trait TransactionalIter { + /// Error type + type Error; + + /// Execute the provided operations on the I2C bus (iterator version). + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + fn exec_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> + where + O: IntoIterator>; +} diff --git a/src/rust/vendor/embedded-hal/src/blocking/mod.rs b/src/rust/vendor/embedded-hal/src/blocking/mod.rs new file mode 100644 index 000000000..e3c132826 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/blocking/mod.rs @@ -0,0 +1,12 @@ +//! Blocking API +//! +//! In some cases it's possible to implement these blocking traits on top of one of the core HAL +//! traits. To save boilerplate when that's the case a `Default` marker trait may be provided. +//! Implementing that marker trait will opt in your type into a blanket implementation. + +pub mod can; +pub mod delay; +pub mod i2c; +pub mod rng; +pub mod serial; +pub mod spi; diff --git a/src/rust/vendor/embedded-hal/src/blocking/rng.rs b/src/rust/vendor/embedded-hal/src/blocking/rng.rs new file mode 100644 index 000000000..cd8a543b6 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/blocking/rng.rs @@ -0,0 +1,19 @@ +//! Blocking hardware random number generator + +/// Blocking read +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +#[cfg(feature = "unproven")] +pub trait Read { + /// Error type + type Error; + + /// Reads enough bytes from hardware random number generator to fill `buffer` + /// + /// If any error is encountered then this function immediately returns. The contents of buf are + /// unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it has read, but it + /// will never read more than would be necessary to completely fill the buffer. + fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error>; +} diff --git a/src/rust/vendor/embedded-hal/src/blocking/serial.rs b/src/rust/vendor/embedded-hal/src/blocking/serial.rs new file mode 100644 index 000000000..6b7c35218 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/blocking/serial.rs @@ -0,0 +1,54 @@ +//! Blocking serial API + +/// Write half of a serial interface (blocking variant) +pub trait Write { + /// The type of error that can occur when writing + type Error; + + /// Writes a slice, blocking until everything has been written + /// + /// An implementation can choose to buffer the write, returning `Ok(())` + /// after the complete slice has been written to a buffer, but before all + /// words have been sent via the serial interface. To make sure that + /// everything has been sent, call [`bflush`] after this function returns. + /// + /// [`bflush`]: #tymethod.bflush + fn bwrite_all(&mut self, buffer: &[Word]) -> Result<(), Self::Error>; + + /// Block until the serial interface has sent all buffered words + fn bflush(&mut self) -> Result<(), Self::Error>; +} + +/// Blocking serial write +pub mod write { + /// Marker trait to opt into default blocking write implementation + /// + /// Implementers of [`serial::Write`] can implement this marker trait + /// for their type. Doing so will automatically provide the default + /// implementation of [`blocking::serial::Write`] for the type. + /// + /// [`serial::Write`]: ../../serial/trait.Write.html + /// [`blocking::serial::Write`]: ../trait.Write.html + pub trait Default: ::serial::Write {} + + impl ::blocking::serial::Write for S + where + S: Default, + Word: Clone, + { + type Error = S::Error; + + fn bwrite_all(&mut self, buffer: &[Word]) -> Result<(), Self::Error> { + for word in buffer { + block!(self.write(word.clone()))?; + } + + Ok(()) + } + + fn bflush(&mut self) -> Result<(), Self::Error> { + block!(self.flush())?; + Ok(()) + } + } +} diff --git a/src/rust/vendor/embedded-hal/src/blocking/spi.rs b/src/rust/vendor/embedded-hal/src/blocking/spi.rs new file mode 100644 index 000000000..76623e290 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/blocking/spi.rs @@ -0,0 +1,127 @@ +//! Blocking SPI API + +/// Blocking transfer +pub trait Transfer { + /// Error type + type Error; + + /// Sends `words` to the slave. Returns the `words` received from the slave + fn transfer<'w>(&mut self, words: &'w mut [W]) -> Result<&'w [W], Self::Error>; +} + +/// Blocking write +pub trait Write { + /// Error type + type Error; + + /// Sends `words` to the slave, ignoring all the incoming words + fn write(&mut self, words: &[W]) -> Result<(), Self::Error>; +} + +/// Blocking write (iterator version) +#[cfg(feature = "unproven")] +pub trait WriteIter { + /// Error type + type Error; + + /// Sends `words` to the slave, ignoring all the incoming words + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator; +} + +/// Blocking transfer +pub mod transfer { + /// Default implementation of `blocking::spi::Transfer` for implementers of + /// `spi::FullDuplex` + pub trait Default: ::spi::FullDuplex {} + + impl ::blocking::spi::Transfer for S + where + S: Default, + W: Clone, + { + type Error = S::Error; + + fn transfer<'w>(&mut self, words: &'w mut [W]) -> Result<&'w [W], S::Error> { + for word in words.iter_mut() { + block!(self.send(word.clone()))?; + *word = block!(self.read())?; + } + + Ok(words) + } + } +} + +/// Blocking write +pub mod write { + /// Default implementation of `blocking::spi::Write` for implementers of `spi::FullDuplex` + pub trait Default: ::spi::FullDuplex {} + + impl ::blocking::spi::Write for S + where + S: Default, + W: Clone, + { + type Error = S::Error; + + fn write(&mut self, words: &[W]) -> Result<(), S::Error> { + for word in words { + block!(self.send(word.clone()))?; + block!(self.read())?; + } + + Ok(()) + } + } +} + +/// Blocking write (iterator version) +#[cfg(feature = "unproven")] +pub mod write_iter { + /// Default implementation of `blocking::spi::WriteIter` for implementers of + /// `spi::FullDuplex` + pub trait Default: ::spi::FullDuplex {} + + impl ::blocking::spi::WriteIter for S + where + S: Default, + W: Clone, + { + type Error = S::Error; + + fn write_iter(&mut self, words: WI) -> Result<(), S::Error> + where + WI: IntoIterator, + { + for word in words.into_iter() { + block!(self.send(word.clone()))?; + block!(self.read())?; + } + + Ok(()) + } + } +} + +/// Operation for transactional SPI trait +/// +/// This allows composition of SPI operations into a single bus transaction +#[derive(Debug, PartialEq)] +pub enum Operation<'a, W: 'static> { + /// Write data from the provided buffer, discarding read data + Write(&'a [W]), + /// Write data out while reading data into the provided buffer + Transfer(&'a mut [W]), +} + +/// Transactional trait allows multiple actions to be executed +/// as part of a single SPI transaction +pub trait Transactional { + /// Associated error type + type Error; + + /// Execute the provided transactions + fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>; +} diff --git a/src/rust/vendor/embedded-hal/src/can/id.rs b/src/rust/vendor/embedded-hal/src/can/id.rs new file mode 100644 index 000000000..811baa5f1 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/can/id.rs @@ -0,0 +1,160 @@ +//! CAN Identifiers. + +/// Standard 11-bit CAN Identifier (`0..=0x7FF`). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct StandardId(u16); + +impl StandardId { + /// CAN ID `0`, the highest priority. + pub const ZERO: Self = StandardId(0); + + /// CAN ID `0x7FF`, the lowest priority. + pub const MAX: Self = StandardId(0x7FF); + + /// Tries to create a `StandardId` from a raw 16-bit integer. + /// + /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`). + #[inline] + pub fn new(raw: u16) -> Option { + if raw <= 0x7FF { + Some(StandardId(raw)) + } else { + None + } + } + + /// Creates a new `StandardId` without checking if it is inside the valid range. + /// + /// # Safety + /// Using this method can create an invalid ID and is thus marked as unsafe. + #[inline] + pub const unsafe fn new_unchecked(raw: u16) -> Self { + StandardId(raw) + } + + /// Returns this CAN Identifier as a raw 16-bit integer. + #[inline] + pub fn as_raw(&self) -> u16 { + self.0 + } +} + +/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct ExtendedId(u32); + +impl ExtendedId { + /// CAN ID `0`, the highest priority. + pub const ZERO: Self = ExtendedId(0); + + /// CAN ID `0x1FFFFFFF`, the lowest priority. + pub const MAX: Self = ExtendedId(0x1FFF_FFFF); + + /// Tries to create a `ExtendedId` from a raw 32-bit integer. + /// + /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`). + #[inline] + pub fn new(raw: u32) -> Option { + if raw <= 0x1FFF_FFFF { + Some(ExtendedId(raw)) + } else { + None + } + } + + /// Creates a new `ExtendedId` without checking if it is inside the valid range. + /// + /// # Safety + /// Using this method can create an invalid ID and is thus marked as unsafe. + #[inline] + pub const unsafe fn new_unchecked(raw: u32) -> Self { + ExtendedId(raw) + } + + /// Returns this CAN Identifier as a raw 32-bit integer. + #[inline] + pub fn as_raw(&self) -> u32 { + self.0 + } + + /// Returns the Base ID part of this extended identifier. + pub fn standard_id(&self) -> StandardId { + // ID-28 to ID-18 + StandardId((self.0 >> 18) as u16) + } +} + +/// A CAN Identifier (standard or extended). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Id { + /// Standard 11-bit Identifier (`0..=0x7FF`). + Standard(StandardId), + + /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`). + Extended(ExtendedId), +} + +impl From for Id { + #[inline] + fn from(id: StandardId) -> Self { + Id::Standard(id) + } +} + +impl From for Id { + #[inline] + fn from(id: ExtendedId) -> Self { + Id::Extended(id) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn standard_id_new() { + assert_eq!( + StandardId::new(StandardId::MAX.as_raw()), + Some(StandardId::MAX) + ); + } + + #[test] + fn standard_id_new_out_of_range() { + assert_eq!(StandardId::new(StandardId::MAX.as_raw() + 1), None); + } + + #[test] + fn standard_id_new_unchecked_out_of_range() { + let id = StandardId::MAX.as_raw() + 1; + assert_eq!(unsafe { StandardId::new_unchecked(id) }, StandardId(id)); + } + + #[test] + fn extended_id_new() { + assert_eq!( + ExtendedId::new(ExtendedId::MAX.as_raw()), + Some(ExtendedId::MAX) + ); + } + + #[test] + fn extended_id_new_out_of_range() { + assert_eq!(ExtendedId::new(ExtendedId::MAX.as_raw() + 1), None); + } + + #[test] + fn extended_id_new_unchecked_out_of_range() { + let id = ExtendedId::MAX.as_raw() + 1; + assert_eq!(unsafe { ExtendedId::new_unchecked(id) }, ExtendedId(id)); + } + + #[test] + fn get_standard_id_from_extended_id() { + assert_eq!( + Some(ExtendedId::MAX.standard_id()), + StandardId::new((ExtendedId::MAX.0 >> 18) as u16) + ); + } +} diff --git a/src/rust/vendor/embedded-hal/src/can/mod.rs b/src/rust/vendor/embedded-hal/src/can/mod.rs new file mode 100644 index 000000000..c12e40a7f --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/can/mod.rs @@ -0,0 +1,123 @@ +//! Controller Area Network + +pub mod nb; + +mod id; + +pub use self::id::*; +pub use self::nb::*; + +/// A CAN2.0 Frame +pub trait Frame: Sized { + /// Creates a new frame. + /// + /// This will return `None` if the data slice is too long. + fn new(id: impl Into, data: &[u8]) -> Option; + + /// Creates a new remote frame (RTR bit set). + /// + /// This will return `None` if the data length code (DLC) is not valid. + fn new_remote(id: impl Into, dlc: usize) -> Option; + + /// Returns true if this frame is a extended frame. + fn is_extended(&self) -> bool; + + /// Returns true if this frame is a standard frame. + fn is_standard(&self) -> bool { + !self.is_extended() + } + + /// Returns true if this frame is a remote frame. + fn is_remote_frame(&self) -> bool; + + /// Returns true if this frame is a data frame. + fn is_data_frame(&self) -> bool { + !self.is_remote_frame() + } + + /// Returns the frame identifier. + fn id(&self) -> Id; + + /// Returns the data length code (DLC) which is in the range 0..8. + /// + /// For data frames the DLC value always matches the length of the data. + /// Remote frames do not carry any data, yet the DLC can be greater than 0. + fn dlc(&self) -> usize; + + /// Returns the frame data (0..8 bytes in length). + fn data(&self) -> &[u8]; +} + +/// CAN error +pub trait Error: core::fmt::Debug { + /// Convert error to a generic CAN error kind + /// + /// By using this method, CAN errors freely defined by HAL implementations + /// can be converted to a set of generic serial errors upon which generic + /// code can act. + fn kind(&self) -> ErrorKind; +} + +/// CAN error kind +/// +/// This represents a common set of CAN operation errors. HAL implementations are +/// free to define more specific or additional error types. However, by providing +/// a mapping to these common CAN errors, generic code can still react to them. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum ErrorKind { + /// The peripheral receive buffer was overrun. + Overrun, + + // MAC sublayer errors + /// A bit error is detected at that bit time when the bit value that is + /// monitored differs from the bit value sent. + Bit, + + /// A stuff error is detected at the bit time of the sixth consecutive + /// equal bit level in a frame field that shall be coded by the method + /// of bit stuffing. + Stuff, + + /// Calculated CRC sequence does not equal the received one. + Crc, + + /// A form error shall be detected when a fixed-form bit field contains + /// one or more illegal bits. + Form, + + /// An ACK error shall be detected by a transmitter whenever it does not + /// monitor a dominant bit during the ACK slot. + Acknowledge, + + /// A different error occurred. The original error may contain more information. + Other, +} + +impl Error for ErrorKind { + fn kind(&self) -> ErrorKind { + *self + } +} + +impl core::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ErrorKind::Overrun => write!(f, "The peripheral receive buffer was overrun"), + ErrorKind::Bit => write!( + f, + "Bit value that is monitored differs from the bit value sent" + ), + ErrorKind::Stuff => write!(f, "Sixth consecutive equal bits detected"), + ErrorKind::Crc => write!(f, "Calculated CRC sequence does not equal the received one"), + ErrorKind::Form => write!( + f, + "A fixed-form bit field contains one or more illegal bits" + ), + ErrorKind::Acknowledge => write!(f, "Transmitted frame was not acknowledged"), + ErrorKind::Other => write!( + f, + "A different error occurred. The original error may contain more information" + ), + } + } +} diff --git a/src/rust/vendor/embedded-hal/src/can/nb.rs b/src/rust/vendor/embedded-hal/src/can/nb.rs new file mode 100644 index 000000000..2ab6050a5 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/can/nb.rs @@ -0,0 +1,28 @@ +//! Non-blocking CAN API + +/// A CAN interface that is able to transmit and receive frames. +pub trait Can { + /// Associated frame type. + type Frame: crate::can::Frame; + + /// Associated error type. + type Error: crate::can::Error; + + /// Puts a frame in the transmit buffer to be sent on the bus. + /// + /// If the transmit buffer is full, this function will try to replace a pending + /// lower priority frame and return the frame that was replaced. + /// Returns `Err(WouldBlock)` if the transmit buffer is full and no frame can be + /// replaced. + /// + /// # Notes for implementers + /// + /// * Frames of equal identifier shall be transmited in FIFO fashion when more + /// than one transmit buffer is available. + /// * When replacing pending frames make sure the frame is not in the process of + /// being send to the bus. + fn transmit(&mut self, frame: &Self::Frame) -> nb::Result, Self::Error>; + + /// Returns a received frame if available. + fn receive(&mut self) -> nb::Result; +} diff --git a/src/rust/vendor/embedded-hal/src/digital/mod.rs b/src/rust/vendor/embedded-hal/src/digital/mod.rs new file mode 100644 index 000000000..5e1848f02 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/digital/mod.rs @@ -0,0 +1,27 @@ +//! Digital I/O +//! +//! +//! + +// Deprecated / infallible traits +#[deprecated( + since = "0.2.2", + note = "Deprecated because the methods cannot return errors. \ + Users should use the traits in digital::v2." +)] +pub mod v1; + +// New / fallible traits +pub mod v2; + +// v2 -> v1 compatibility wrappers +// These require explicit casts from v2 -> v1 +pub mod v1_compat; + +// v1 -> v2 compatibility shims +// These are implicit over v1 implementations +pub mod v2_compat; + +// Re-export old traits so this isn't a breaking change +#[allow(deprecated)] +pub use self::v1::*; diff --git a/src/rust/vendor/embedded-hal/src/digital/v1.rs b/src/rust/vendor/embedded-hal/src/digital/v1.rs new file mode 100644 index 000000000..d7bbfacaa --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/digital/v1.rs @@ -0,0 +1,145 @@ +//! Digital I/O +//! +//! The traits in this module are now deprecated. Please use the new versions included +//! in `digital::v2`. + +#![allow(deprecated)] + +/// Single digital push-pull output pin +/// +/// *This version of the trait is now deprecated. Please use the new `OutputPin` trait in +/// `digital::v2::OutputPin`*. + +pub trait OutputPin { + /// Drives the pin low + /// + /// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external + /// electrical sources + fn set_low(&mut self); + + /// Drives the pin high + /// + /// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external + /// electrical sources + fn set_high(&mut self); +} + +/// Push-pull output pin that can read its output state +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// *This version of the trait is now deprecated. Please use the new `StatefulOutputPin` trait in +/// `digital::v2::StatefulOutputPin`*. +#[cfg(feature = "unproven")] +pub trait StatefulOutputPin { + /// Is the pin in drive high mode? + /// + /// *NOTE* this does *not* read the electrical state of the pin + fn is_set_high(&self) -> bool; + + /// Is the pin in drive low mode? + /// + /// *NOTE* this does *not* read the electrical state of the pin + fn is_set_low(&self) -> bool; +} + +/// Output pin that can be toggled +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// *This version of the trait is now deprecated. Please use the new `ToggleableOutputPin` +/// trait in `digital::v2::ToggleableOutputPin`*. +/// +/// See [toggleable](toggleable) to use a software implementation if +/// both [OutputPin](trait.OutputPin.html) and +/// [StatefulOutputPin](trait.StatefulOutputPin.html) are +/// implemented. Otherwise, implement this using hardware mechanisms. +#[cfg(feature = "unproven")] +pub trait ToggleableOutputPin { + /// Toggle pin output. + fn toggle(&mut self); +} + +/// If you can read **and** write the output state, a pin is +/// toggleable by software. +/// +/// *This version of the module is now deprecated. Please use the new `toggleable` module in +/// `digital::v2::toggleable`*. +/// +/// ``` +/// use embedded_hal::digital::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; +/// use embedded_hal::digital::toggleable; +/// +/// /// A virtual output pin that exists purely in software +/// struct MyPin { +/// state: bool +/// } +/// +/// impl OutputPin for MyPin { +/// fn set_low(&mut self) { +/// self.state = false; +/// } +/// fn set_high(&mut self) { +/// self.state = true; +/// } +/// } +/// +/// impl StatefulOutputPin for MyPin { +/// fn is_set_low(&self) -> bool { +/// !self.state +/// } +/// fn is_set_high(&self) -> bool { +/// self.state +/// } +/// } +/// +/// /// Opt-in to the software implementation. +/// impl toggleable::Default for MyPin {} +/// +/// let mut pin = MyPin { state: false }; +/// pin.toggle(); +/// assert!(pin.is_set_high()); +/// pin.toggle(); +/// assert!(pin.is_set_low()); +/// ``` +#[cfg(feature = "unproven")] +pub mod toggleable { + #[allow(deprecated)] + use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; + + /// Software-driven `toggle()` implementation. + /// + /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* + #[allow(deprecated)] + pub trait Default: OutputPin + StatefulOutputPin {} + + #[allow(deprecated)] + impl

ToggleableOutputPin for P + where + P: Default, + { + /// Toggle pin output + fn toggle(&mut self) { + if self.is_set_low() { + self.set_high(); + } else { + self.set_low(); + } + } + } +} + +/// Single digital input pin +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// *This version of the trait is now deprecated. Please use the new `InputPin` trait in +/// `digital::v2::InputPin`*. +#[cfg(feature = "unproven")] +pub trait InputPin { + /// Is the input pin high? + fn is_high(&self) -> bool; + + /// Is the input pin low? + fn is_low(&self) -> bool; +} diff --git a/src/rust/vendor/embedded-hal/src/digital/v1_compat.rs b/src/rust/vendor/embedded-hal/src/digital/v1_compat.rs new file mode 100644 index 000000000..83a9ffce7 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/digital/v1_compat.rs @@ -0,0 +1,298 @@ +//! v1 compatibility wrappers +//! +//! This module provides wrappers to support use of v2 implementations with +//! v1 consumers. v2 traits must be explicitly cast to the v1 version using +//! `.into()`, and will panic on internal errors +//! +//! ``` +//! extern crate embedded_hal; +//! use embedded_hal::digital::{v1, v2, v1_compat::OldOutputPin}; +//! +//! struct NewOutputPinImpl {} +//! +//! impl v2::OutputPin for NewOutputPinImpl { +//! type Error = (); +//! fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) } +//! fn set_high(&mut self) -> Result<(), Self::Error>{ Ok(()) } +//! } +//! +//! struct OldOutputPinConsumer { +//! _pin: T, +//! } +//! +//! impl OldOutputPinConsumer +//! where T: v1::OutputPin { +//! pub fn new(pin: T) -> OldOutputPinConsumer { +//! OldOutputPinConsumer{ _pin: pin } +//! } +//! } +//! +//! fn main() { +//! let pin = NewOutputPinImpl{}; +//! let _consumer: OldOutputPinConsumer> = OldOutputPinConsumer::new(pin.into()); +//! } +//! ``` +//! + +#[allow(deprecated)] +use super::v1; +use super::v2; + +/// Wrapper to allow fallible `v2::OutputPin` traits to be converted to `v1::OutputPin` traits +pub struct OldOutputPin { + pin: T, +} + +impl OldOutputPin +where + T: v2::OutputPin, + E: core::fmt::Debug, +{ + /// Create a new OldOutputPin wrapper around a `v2::OutputPin` + pub fn new(pin: T) -> Self { + Self { pin } + } + + /// Fetch a reference to the inner `v2::OutputPin` impl + #[cfg(test)] + fn inner(&self) -> &T { + &self.pin + } +} + +impl From for OldOutputPin +where + T: v2::OutputPin, + E: core::fmt::Debug, +{ + fn from(pin: T) -> Self { + OldOutputPin { pin } + } +} + +/// Implementation of `v1::OutputPin` trait for fallible `v2::OutputPin` output pins +/// where errors will panic. +#[allow(deprecated)] +impl v1::OutputPin for OldOutputPin +where + T: v2::OutputPin, + E: core::fmt::Debug, +{ + fn set_low(&mut self) { + self.pin.set_low().unwrap() + } + + fn set_high(&mut self) { + self.pin.set_high().unwrap() + } +} + +/// Implementation of `v1::StatefulOutputPin` trait for `v2::StatefulOutputPin` fallible pins +/// where errors will panic. +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v1::StatefulOutputPin for OldOutputPin +where + T: v2::StatefulOutputPin, + E: core::fmt::Debug, +{ + fn is_set_low(&self) -> bool { + self.pin.is_set_low().unwrap() + } + + fn is_set_high(&self) -> bool { + self.pin.is_set_high().unwrap() + } +} + +/// Wrapper to allow fallible `v2::InputPin` traits to be converted to `v1::InputPin` traits +/// where errors will panic. +#[cfg(feature = "unproven")] +pub struct OldInputPin { + pin: T, +} + +#[cfg(feature = "unproven")] +impl OldInputPin +where + T: v2::InputPin, + E: core::fmt::Debug, +{ + /// Create an `OldInputPin` wrapper around a `v2::InputPin`. + pub fn new(pin: T) -> Self { + Self { pin } + } +} + +#[cfg(feature = "unproven")] +impl From for OldInputPin +where + T: v2::InputPin, + E: core::fmt::Debug, +{ + fn from(pin: T) -> Self { + OldInputPin { pin } + } +} + +/// Implementation of `v1::InputPin` trait for `v2::InputPin` fallible pins +/// where errors will panic. +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v1::InputPin for OldInputPin +where + T: v2::InputPin, + E: core::fmt::Debug, +{ + fn is_low(&self) -> bool { + self.pin.is_low().unwrap() + } + + fn is_high(&self) -> bool { + self.pin.is_high().unwrap() + } +} + +#[cfg(test)] +#[allow(deprecated)] +mod tests { + use super::*; + + #[allow(deprecated)] + use crate::digital::v1; + use crate::digital::v2; + + use crate::digital::v1::OutputPin; + + #[derive(Clone)] + struct NewOutputPinImpl { + state: bool, + res: Result<(), ()>, + } + + impl v2::OutputPin for NewOutputPinImpl { + type Error = (); + + fn set_low(&mut self) -> Result<(), Self::Error> { + self.state = false; + self.res + } + fn set_high(&mut self) -> Result<(), Self::Error> { + self.state = true; + self.res + } + } + + #[allow(deprecated)] + struct OldOutputPinConsumer { + _pin: T, + } + + #[allow(deprecated)] + impl OldOutputPinConsumer + where + T: v1::OutputPin, + { + pub fn new(pin: T) -> OldOutputPinConsumer { + OldOutputPinConsumer { _pin: pin } + } + } + + #[test] + fn v1_v2_output_explicit() { + let i = NewOutputPinImpl { + state: false, + res: Ok(()), + }; + let _c: OldOutputPinConsumer> = OldOutputPinConsumer::new(i.into()); + } + + #[test] + fn v1_v2_output_state() { + let mut o: OldOutputPin<_> = NewOutputPinImpl { + state: false, + res: Ok(()), + } + .into(); + + o.set_high(); + assert_eq!(o.inner().state, true); + + o.set_low(); + assert_eq!(o.inner().state, false); + } + + #[test] + #[should_panic] + fn v1_v2_output_panic() { + let mut o: OldOutputPin<_> = NewOutputPinImpl { + state: false, + res: Err(()), + } + .into(); + + o.set_high(); + } + + #[cfg(feature = "unproven")] + use crate::digital::v1::InputPin; + + #[cfg(feature = "unproven")] + struct NewInputPinImpl { + state: Result, + } + + #[cfg(feature = "unproven")] + impl v2::InputPin for NewInputPinImpl { + type Error = (); + + fn is_low(&self) -> Result { + self.state.map(|v| v == false) + } + fn is_high(&self) -> Result { + self.state.map(|v| v == true) + } + } + + #[cfg(feature = "unproven")] + #[allow(deprecated)] + struct OldInputPinConsumer { + _pin: T, + } + + #[cfg(feature = "unproven")] + #[allow(deprecated)] + impl OldInputPinConsumer + where + T: v1::InputPin, + { + pub fn new(pin: T) -> OldInputPinConsumer { + OldInputPinConsumer { _pin: pin } + } + } + + #[cfg(feature = "unproven")] + #[test] + fn v1_v2_input_explicit() { + let i = NewInputPinImpl { state: Ok(false) }; + let _c: OldInputPinConsumer> = OldInputPinConsumer::new(i.into()); + } + + #[cfg(feature = "unproven")] + #[test] + fn v1_v2_input_state() { + let i: OldInputPin<_> = NewInputPinImpl { state: Ok(false) }.into(); + + assert_eq!(i.is_low(), true); + assert_eq!(i.is_high(), false); + } + + #[cfg(feature = "unproven")] + #[test] + #[should_panic] + fn v1_v2_input_panic() { + let i: OldInputPin<_> = NewInputPinImpl { state: Err(()) }.into(); + + i.is_low(); + } +} diff --git a/src/rust/vendor/embedded-hal/src/digital/v2.rs b/src/rust/vendor/embedded-hal/src/digital/v2.rs new file mode 100644 index 000000000..81fd67cbb --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/digital/v2.rs @@ -0,0 +1,216 @@ +//! Digital I/O +//! +//! Version 2 / fallible traits. Infallible implementations should set Error to `!`. + +use core::{convert::From, ops::Not}; + +/// Digital output pin state +/// +/// Conversion from `bool` and logical negation are also implemented +/// for this type. +/// ```rust +/// # use embedded_hal::digital::v2::PinState; +/// let state = PinState::from(false); +/// assert_eq!(state, PinState::Low); +/// assert_eq!(!state, PinState::High); +/// ``` +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PinState { + /// Low pin state + Low, + /// High pin state + High, +} + +impl From for PinState { + fn from(value: bool) -> Self { + match value { + false => PinState::Low, + true => PinState::High, + } + } +} + +impl Not for PinState { + type Output = PinState; + + fn not(self) -> Self::Output { + match self { + PinState::High => PinState::Low, + PinState::Low => PinState::High, + } + } +} + +/// Single digital push-pull output pin +pub trait OutputPin { + /// Error type + type Error; + + /// Drives the pin low + /// + /// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external + /// electrical sources + fn set_low(&mut self) -> Result<(), Self::Error>; + + /// Drives the pin high + /// + /// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external + /// electrical sources + fn set_high(&mut self) -> Result<(), Self::Error>; + + /// Drives the pin high or low depending on the provided value + /// + /// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external + /// electrical sources + fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } +} + +/// Push-pull output pin that can read its output state +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +#[cfg(feature = "unproven")] +pub trait StatefulOutputPin: OutputPin { + /// Is the pin in drive high mode? + /// + /// *NOTE* this does *not* read the electrical state of the pin + fn is_set_high(&self) -> Result; + + /// Is the pin in drive low mode? + /// + /// *NOTE* this does *not* read the electrical state of the pin + fn is_set_low(&self) -> Result; +} + +/// Output pin that can be toggled +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// See [toggleable](toggleable) to use a software implementation if +/// both [OutputPin](trait.OutputPin.html) and +/// [StatefulOutputPin](trait.StatefulOutputPin.html) are +/// implemented. Otherwise, implement this using hardware mechanisms. +#[cfg(feature = "unproven")] +pub trait ToggleableOutputPin { + /// Error type + type Error; + + /// Toggle pin output. + fn toggle(&mut self) -> Result<(), Self::Error>; +} + +/// If you can read **and** write the output state, a pin is +/// toggleable by software. +/// +/// ``` +/// use embedded_hal::digital::v2::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; +/// use embedded_hal::digital::v2::toggleable; +/// +/// /// A virtual output pin that exists purely in software +/// struct MyPin { +/// state: bool +/// } +/// +/// impl OutputPin for MyPin { +/// type Error = void::Void; +/// +/// fn set_low(&mut self) -> Result<(), Self::Error> { +/// self.state = false; +/// Ok(()) +/// } +/// fn set_high(&mut self) -> Result<(), Self::Error> { +/// self.state = true; +/// Ok(()) +/// } +/// } +/// +/// impl StatefulOutputPin for MyPin { +/// fn is_set_low(&self) -> Result { +/// Ok(!self.state) +/// } +/// fn is_set_high(&self) -> Result { +/// Ok(self.state) +/// } +/// } +/// +/// /// Opt-in to the software implementation. +/// impl toggleable::Default for MyPin {} +/// +/// let mut pin = MyPin { state: false }; +/// pin.toggle().unwrap(); +/// assert!(pin.is_set_high().unwrap()); +/// pin.toggle().unwrap(); +/// assert!(pin.is_set_low().unwrap()); +/// ``` +#[cfg(feature = "unproven")] +pub mod toggleable { + use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin}; + + /// Software-driven `toggle()` implementation. + /// + /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* + pub trait Default: OutputPin + StatefulOutputPin {} + + impl

ToggleableOutputPin for P + where + P: Default, + { + type Error = P::Error; + + /// Toggle pin output + fn toggle(&mut self) -> Result<(), Self::Error> { + if self.is_set_low()? { + self.set_high() + } else { + self.set_low() + } + } + } +} + +/// Single digital input pin +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +#[cfg(feature = "unproven")] +pub trait InputPin { + /// Error type + type Error; + + /// Is the input pin high? + fn is_high(&self) -> Result; + + /// Is the input pin low? + fn is_low(&self) -> Result; +} + +/// Single pin that can switch from input to output mode, and vice-versa. +/// +/// Example use (assumes the `Error` type is the same for the `IoPin`, +/// `InputPin`, and `OutputPin`): +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +#[cfg(feature = "unproven")] +pub trait IoPin +where + TInput: InputPin + IoPin, + TOutput: OutputPin + IoPin, +{ + /// Error type. + type Error; + + /// Tries to convert this pin to input mode. + /// + /// If the pin is already in input mode, this method should succeed. + fn into_input_pin(self) -> Result; + + /// Tries to convert this pin to output mode with the given initial state. + /// + /// If the pin is already in the requested state, this method should + /// succeed. + fn into_output_pin(self, state: PinState) -> Result; +} diff --git a/src/rust/vendor/embedded-hal/src/digital/v2_compat.rs b/src/rust/vendor/embedded-hal/src/digital/v2_compat.rs new file mode 100644 index 000000000..929f413dd --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/digital/v2_compat.rs @@ -0,0 +1,234 @@ +//! v2 compatibility shims +//! +//! This module adds implicit forward support to v1 digital traits, +//! allowing v1 implementations to be directly used with v2 consumers. +//! +//! ``` +//! extern crate embedded_hal; +//! use embedded_hal::digital::{v1, v2}; +//! +//! struct OldOutputPinImpl { } +//! +//! impl v1::OutputPin for OldOutputPinImpl { +//! fn set_low(&mut self) { } +//! fn set_high(&mut self) { } +//! } +//! +//! struct NewOutputPinConsumer { +//! _pin: T, +//! } +//! +//! impl NewOutputPinConsumer +//! where T: v2::OutputPin { +//! pub fn new(pin: T) -> NewOutputPinConsumer { +//! NewOutputPinConsumer{ _pin: pin } +//! } +//! } +//! +//! fn main() { +//! let pin = OldOutputPinImpl{}; +//! let _consumer = NewOutputPinConsumer::new(pin); +//! } +//! ``` +//! + +#[allow(deprecated)] +use super::v1; +use super::v2; + +/// Implementation of fallible `v2::OutputPin` for `v1::OutputPin` traits +#[allow(deprecated)] +impl v2::OutputPin for T +where + T: v1::OutputPin, +{ + // TODO: update to ! when never_type is stabilized + type Error = (); + + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } +} + +/// Implementation of fallible `v2::StatefulOutputPin` for `v1::StatefulOutputPin` digital traits +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v2::StatefulOutputPin for T +where + T: v1::StatefulOutputPin + v1::OutputPin, +{ + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } +} + +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v2::toggleable::Default for T where T: v1::toggleable::Default {} + +/// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v2::InputPin for T +where + T: v1::InputPin, +{ + // TODO: update to ! when never_type is stabilized + type Error = (); + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } + + fn is_high(&self) -> Result { + Ok(self.is_high()) + } +} + +#[cfg(test)] +mod tests { + + #[allow(deprecated)] + use crate::digital::v1; + use crate::digital::v2; + + #[allow(deprecated)] + struct OldOutputPinImpl { + state: bool, + } + + #[allow(deprecated)] + impl v1::OutputPin for OldOutputPinImpl { + fn set_low(&mut self) { + self.state = false; + } + fn set_high(&mut self) { + self.state = true; + } + } + + #[allow(deprecated)] + #[cfg(feature = "unproven")] + impl v1::StatefulOutputPin for OldOutputPinImpl { + fn is_set_low(&self) -> bool { + self.state == false + } + + fn is_set_high(&self) -> bool { + self.state == true + } + } + + #[allow(deprecated)] + #[cfg(feature = "unproven")] + impl v1::toggleable::Default for OldOutputPinImpl {} + + struct NewOutputPinConsumer { + _pin: T, + } + + impl NewOutputPinConsumer + where + T: v2::OutputPin, + { + pub fn new(pin: T) -> NewOutputPinConsumer { + NewOutputPinConsumer { _pin: pin } + } + } + + #[cfg(feature = "unproven")] + struct NewToggleablePinConsumer { + _pin: T, + } + + #[cfg(feature = "unproven")] + impl NewToggleablePinConsumer + where + T: v2::ToggleableOutputPin, + { + pub fn new(pin: T) -> NewToggleablePinConsumer { + NewToggleablePinConsumer { _pin: pin } + } + } + + #[test] + #[cfg(feature = "unproven")] + fn v2_v1_toggleable_implicit() { + let i = OldOutputPinImpl { state: false }; + let _c = NewToggleablePinConsumer::new(i); + } + + #[test] + fn v2_v1_output_implicit() { + let i = OldOutputPinImpl { state: false }; + let _c = NewOutputPinConsumer::new(i); + } + + #[test] + fn v2_v1_output_state() { + let mut o = OldOutputPinImpl { state: false }; + + v2::OutputPin::set_high(&mut o).unwrap(); + assert_eq!(o.state, true); + + v2::OutputPin::set_low(&mut o).unwrap(); + assert_eq!(o.state, false); + } + + #[cfg(feature = "unproven")] + #[allow(deprecated)] + struct OldInputPinImpl { + state: bool, + } + + #[cfg(feature = "unproven")] + #[allow(deprecated)] + impl v1::InputPin for OldInputPinImpl { + fn is_low(&self) -> bool { + !self.state + } + fn is_high(&self) -> bool { + self.state + } + } + + #[cfg(feature = "unproven")] + struct NewInputPinConsumer { + _pin: T, + } + + #[cfg(feature = "unproven")] + impl NewInputPinConsumer + where + T: v2::InputPin, + { + pub fn new(pin: T) -> NewInputPinConsumer { + NewInputPinConsumer { _pin: pin } + } + } + + #[cfg(feature = "unproven")] + #[test] + #[cfg(feature = "unproven")] + fn v2_v1_input_implicit() { + let i = OldInputPinImpl { state: false }; + let _c = NewInputPinConsumer::new(i); + } + + #[cfg(feature = "unproven")] + #[test] + fn v2_v1_input_state() { + let mut i = OldInputPinImpl { state: false }; + + assert_eq!(v2::InputPin::is_high(&mut i).unwrap(), false); + assert_eq!(v2::InputPin::is_low(&mut i).unwrap(), true); + } +} diff --git a/src/rust/vendor/embedded-hal/src/fmt.rs b/src/rust/vendor/embedded-hal/src/fmt.rs new file mode 100644 index 000000000..33041a84f --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/fmt.rs @@ -0,0 +1,18 @@ +//! Implementation of `core::fmt::Write` for the HAL's `serial::Write`. +//! +//! TODO write example of usage +use core::fmt::{Result, Write}; + +impl Write for dyn (::serial::Write) +where + Word: From, +{ + fn write_str(&mut self, s: &str) -> Result { + let _ = s + .as_bytes() + .into_iter() + .map(|c| block!(self.write(Word::from(*c)))) + .last(); + Ok(()) + } +} diff --git a/src/rust/vendor/embedded-hal/src/lib.rs b/src/rust/vendor/embedded-hal/src/lib.rs new file mode 100644 index 000000000..f0289b2f7 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/lib.rs @@ -0,0 +1,999 @@ +//! A Hardware Abstraction Layer (HAL) for embedded systems +//! +//! **NOTE** This HAL is still is active development. Expect the traits presented here to be +//! tweaked, split or be replaced wholesale before being stabilized, i.e. before hitting the 1.0.0 +//! release. That being said there's a part of the HAL that's currently considered unproven and is +//! hidden behind an "unproven" Cargo feature. This API is even more volatile and it's exempt from +//! semver rules: it can change in a non-backward compatible fashion or even disappear in between +//! patch releases. +//! +//! # Design goals +//! +//! The HAL +//! +//! - Must *erase* device specific details. Neither register, register blocks or magic values should +//! appear in the API. +//! +//! - Must be generic *within* a device and *across* devices. The API to use a serial interface must +//! be the same regardless of whether the implementation uses the USART1 or UART4 peripheral of a +//! device or the UART0 peripheral of another device. +//! +//! - Where possible must *not* be tied to a specific asynchronous model. The API should be usable +//! in blocking mode, with the `futures` model, with an async/await model or with a callback model. +//! (cf. the [`nb`] crate) +//! +//! - Must be minimal, and thus easy to implement and zero cost, yet highly composable. People that +//! want higher level abstraction should *prefer to use this HAL* rather than *re-implement* +//! register manipulation code. +//! +//! - Serve as a foundation for building an ecosystem of platform agnostic drivers. Here driver +//! means a library crate that lets a target platform interface an external device like a digital +//! sensor or a wireless transceiver. The advantage of this system is that by writing the driver as +//! a generic library on top of `embedded-hal` driver authors can support any number of target +//! platforms (e.g. Cortex-M microcontrollers, AVR microcontrollers, embedded Linux, etc.). The +//! advantage for application developers is that by adopting `embedded-hal` they can unlock all +//! these drivers for their platform. +//! +//! # Out of scope +//! +//! - Initialization and configuration stuff like "ensure this serial interface and that SPI +//! interface are not using the same pins". The HAL will focus on *doing I/O*. +//! +//! # Reference implementation +//! +//! The [`stm32f30x-hal`] crate contains a reference implementation of this HAL. +//! +//! [`stm32f30x-hal`]: https://crates.io/crates/stm32f30x-hal/0.1.0 +//! +//! # Platform agnostic drivers +//! +//! You can find platform agnostic drivers built on top of `embedded-hal` on crates.io by [searching +//! for the *embedded-hal* keyword](https://crates.io/keywords/embedded-hal). +//! +//! If you writing a platform agnostic driver yourself you are highly encouraged to [add the +//! embedded-hal keyword](https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata) +//! to your crate before publishing it! +//! +//! # Detailed design +//! +//! ## Traits +//! +//! The HAL is specified as traits to allow generic programming. These traits make use of the +//! [`nb`][] crate (*please go read that crate documentation before continuing*) to abstract over +//! the asynchronous model and to also provide a blocking operation mode. +//! +//! [`nb`]: https://crates.io/crates/nb +//! +//! Here's how a HAL trait may look like: +//! +//! ``` +//! extern crate nb; +//! +//! /// A serial interface +//! pub trait Serial { +//! /// Error type associated to this serial interface +//! type Error; +//! +//! /// Reads a single byte +//! fn read(&mut self) -> nb::Result; +//! +//! /// Writes a single byte +//! fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error>; +//! } +//! ``` +//! +//! The `nb::Result` enum is used to add a [`WouldBlock`] variant to the errors +//! of the serial interface. As explained in the documentation of the `nb` crate this single API, +//! when paired with the macros in the `nb` crate, can operate in a blocking manner, or in a +//! non-blocking manner compatible with `futures` and with the `await!` operator. +//! +//! [`WouldBlock`]: https://docs.rs/nb/0.1.0/nb/enum.Error.html +//! +//! Some traits, like the one shown below, may expose possibly blocking APIs that can't fail. In +//! those cases `nb::Result<_, Void>` is used. +//! +//! ``` +//! extern crate nb; +//! extern crate void; +//! +//! use void::Void; +//! +//! /// A count down timer +//! pub trait CountDown { +//! // .. +//! +//! /// "waits" until the count down is over +//! fn wait(&mut self) -> nb::Result<(), Void>; +//! } +//! +//! # fn main() {} +//! ``` +//! +//! ## Suggested implementation +//! +//! The HAL traits should be implemented for device crates generated via [`svd2rust`] to maximize +//! code reuse. +//! +//! [`svd2rust`]: https://crates.io/crates/svd2rust +//! +//! Shown below is an implementation of some of the HAL traits for the [`stm32f30x`] crate. This +//! single implementation will work for *any* microcontroller in the STM32F30x family. +//! +//! [`stm32f30x`]: https://crates.io/crates/stm32f30x +//! +//! ``` +//! // crate: stm32f30x-hal +//! // An implementation of the `embedded-hal` traits for STM32F30x microcontrollers +//! +//! extern crate embedded_hal as hal; +//! extern crate nb; +//! +//! // device crate +//! extern crate stm32f30x; +//! +//! use stm32f30x::USART1; +//! +//! /// A serial interface +//! // NOTE generic over the USART peripheral +//! pub struct Serial { usart: USART } +//! +//! // convenience type alias +//! pub type Serial1 = Serial; +//! +//! /// Serial interface error +//! pub enum Error { +//! /// Buffer overrun +//! Overrun, +//! // omitted: other error variants +//! } +//! +//! impl hal::serial::Read for Serial { +//! type Error = Error; +//! +//! fn read(&mut self) -> nb::Result { +//! // read the status register +//! let isr = self.usart.isr.read(); +//! +//! if isr.ore().bit_is_set() { +//! // Error: Buffer overrun +//! Err(nb::Error::Other(Error::Overrun)) +//! } +//! // omitted: checks for other errors +//! else if isr.rxne().bit_is_set() { +//! // Data available: read the data register +//! Ok(self.usart.rdr.read().bits() as u8) +//! } else { +//! // No data available yet +//! Err(nb::Error::WouldBlock) +//! } +//! } +//! } +//! +//! impl hal::serial::Write for Serial { +//! type Error = Error; +//! +//! fn write(&mut self, byte: u8) -> nb::Result<(), Error> { +//! // Similar to the `read` implementation +//! # Ok(()) +//! } +//! +//! fn flush(&mut self) -> nb::Result<(), Error> { +//! // Similar to the `read` implementation +//! # Ok(()) +//! } +//! } +//! +//! # fn main() {} +//! ``` +//! +//! ## Intended usage +//! +//! Thanks to the [`nb`] crate the HAL API can be used in a blocking manner, +//! with `futures` or with the `await` operator using the [`block!`], +//! [`try_nb!`] and [`await!`] macros respectively. +//! +//! [`block!`]: https://docs.rs/nb/0.1.0/nb/macro.block.html +//! [`try_nb!`]: https://docs.rs/nb/0.1.0/nb/index.html#how-to-use-this-crate +//! [`await!`]: https://docs.rs/nb/0.1.0/nb/index.html#how-to-use-this-crate +//! +//! ### Blocking mode +//! +//! An example of sending a string over the serial interface in a blocking +//! fashion: +//! +//! ``` +//! extern crate embedded_hal; +//! #[macro_use(block)] +//! extern crate nb; +//! +//! use stm32f30x_hal::Serial1; +//! use embedded_hal::serial::Write; +//! +//! # fn main() { +//! let mut serial: Serial1 = { +//! // .. +//! # Serial1 +//! }; +//! +//! for byte in b"Hello, world!" { +//! // NOTE `block!` blocks until `serial.write()` completes and returns +//! // `Result<(), Error>` +//! block!(serial.write(*byte)).unwrap(); +//! } +//! # } +//! +//! # mod stm32f30x_hal { +//! # extern crate void; +//! # use self::void::Void; +//! # pub struct Serial1; +//! # impl Serial1 { +//! # pub fn write(&mut self, _: u8) -> ::nb::Result<(), Void> { +//! # Ok(()) +//! # } +//! # } +//! # } +//! ``` +//! +//! ### `futures` +//! +//! An example of running two tasks concurrently. First task: blink an LED every +//! second. Second task: loop back data over the serial interface. +//! +//! ``` +//! extern crate embedded_hal as hal; +//! extern crate futures; +//! extern crate void; +//! +//! #[macro_use(try_nb)] +//! extern crate nb; +//! +//! use hal::prelude::*; +//! use futures::{ +//! future, +//! Async, +//! Future, +//! }; +//! use futures::future::Loop; +//! use stm32f30x_hal::{Led, Serial1, Timer6}; +//! use void::Void; +//! +//! /// `futures` version of `CountDown.wait` +//! /// +//! /// This returns a future that must be polled to completion +//! fn wait(mut timer: T) -> impl Future +//! where +//! T: hal::timer::CountDown, +//! { +//! let mut timer = Some(timer); +//! future::poll_fn(move || { +//! try_nb!(timer.as_mut().unwrap().wait()); +//! +//! Ok(Async::Ready(timer.take().unwrap())) +//! }) +//! } +//! +//! /// `futures` version of `Serial.read` +//! /// +//! /// This returns a future that must be polled to completion +//! fn read(mut serial: S) -> impl Future +//! where +//! S: hal::serial::Read, +//! { +//! let mut serial = Some(serial); +//! future::poll_fn(move || { +//! let byte = try_nb!(serial.as_mut().unwrap().read()); +//! +//! Ok(Async::Ready((serial.take().unwrap(), byte))) +//! }) +//! } +//! +//! /// `futures` version of `Serial.write` +//! /// +//! /// This returns a future that must be polled to completion +//! fn write(mut serial: S, byte: u8) -> impl Future +//! where +//! S: hal::serial::Write, +//! { +//! let mut serial = Some(serial); +//! future::poll_fn(move || { +//! try_nb!(serial.as_mut().unwrap().write(byte)); +//! +//! Ok(Async::Ready(serial.take().unwrap())) +//! }) +//! } +//! +//! fn main() { +//! // HAL implementers +//! let timer: Timer6 = { +//! // .. +//! # Timer6 +//! }; +//! let serial: Serial1 = { +//! // .. +//! # Serial1 +//! }; +//! let led: Led = { +//! // .. +//! # Led +//! }; +//! +//! // Tasks +//! let mut blinky = future::loop_fn::<_, (), _, _>( +//! (led, timer, true), +//! |(mut led, mut timer, state)| { +//! wait(timer).map(move |timer| { +//! if state { +//! led.on(); +//! } else { +//! led.off(); +//! } +//! +//! Loop::Continue((led, timer, !state)) +//! }) +//! }); +//! +//! let mut loopback = future::loop_fn::<_, (), _, _>(serial, |mut serial| { +//! read(serial).and_then(|(serial, byte)| { +//! write(serial, byte) +//! }).map(|serial| { +//! Loop::Continue(serial) +//! }) +//! }); +//! +//! // Event loop +//! loop { +//! blinky.poll().unwrap(); // NOTE(unwrap) E = Void +//! loopback.poll().unwrap(); +//! # break; +//! } +//! } +//! +//! # mod stm32f30x_hal { +//! # extern crate void; +//! # use self::void::Void; +//! # pub struct Timer6; +//! # impl ::hal::timer::CountDown for Timer6 { +//! # type Time = (); +//! # +//! # fn start(&mut self, _: T) where T: Into<()> {} +//! # fn wait(&mut self) -> ::nb::Result<(), Void> { Err(::nb::Error::WouldBlock) } +//! # } +//! # +//! # pub struct Serial1; +//! # impl ::hal::serial::Read for Serial1 { +//! # type Error = Void; +//! # fn read(&mut self) -> ::nb::Result { Err(::nb::Error::WouldBlock) } +//! # } +//! # impl ::hal::serial::Write for Serial1 { +//! # type Error = Void; +//! # fn flush(&mut self) -> ::nb::Result<(), Void> { Err(::nb::Error::WouldBlock) } +//! # fn write(&mut self, _: u8) -> ::nb::Result<(), Void> { Err(::nb::Error::WouldBlock) } +//! # } +//! # +//! # pub struct Led; +//! # impl Led { +//! # pub fn off(&mut self) {} +//! # pub fn on(&mut self) {} +//! # } +//! # } +//! ``` +//! +//! ### `await` +//! +//! Same example as above but using `await!` instead of `futures`. +//! +//! ``` +//! #![feature(generator_trait)] +//! #![feature(generators)] +//! +//! extern crate embedded_hal as hal; +//! +//! #[macro_use(await)] +//! extern crate nb; +//! +//! use std::ops::Generator; +//! use std::pin::Pin; +//! +//! use hal::prelude::*; +//! use stm32f30x_hal::{Led, Serial1, Timer6}; +//! +//! fn main() { +//! // HAL implementers +//! let mut timer: Timer6 = { +//! // .. +//! # Timer6 +//! }; +//! let mut serial: Serial1 = { +//! // .. +//! # Serial1 +//! }; +//! let mut led: Led = { +//! // .. +//! # Led +//! }; +//! +//! // Tasks +//! let mut blinky = (move || { +//! let mut state = false; +//! loop { +//! // `await!` means "suspend / yield here" instead of "block until +//! // completion" +//! await!(timer.wait()).unwrap(); // NOTE(unwrap) E = Void +//! +//! state = !state; +//! +//! if state { +//! led.on(); +//! } else { +//! led.off(); +//! } +//! } +//! }); +//! +//! let mut loopback = (move || { +//! loop { +//! let byte = await!(serial.read()).unwrap(); +//! await!(serial.write(byte)).unwrap(); +//! } +//! }); +//! +//! // Event loop +//! loop { +//! Pin::new(&mut blinky).resume(()); +//! Pin::new(&mut loopback).resume(()); +//! # break; +//! } +//! } +//! +//! # mod stm32f30x_hal { +//! # extern crate void; +//! # use self::void::Void; +//! # pub struct Serial1; +//! # impl Serial1 { +//! # pub fn read(&mut self) -> ::nb::Result { Err(::nb::Error::WouldBlock) } +//! # pub fn write(&mut self, _: u8) -> ::nb::Result<(), Void> { Err(::nb::Error::WouldBlock) } +//! # } +//! # pub struct Timer6; +//! # impl Timer6 { +//! # pub fn wait(&mut self) -> ::nb::Result<(), Void> { Err(::nb::Error::WouldBlock) } +//! # } +//! # pub struct Led; +//! # impl Led { +//! # pub fn off(&mut self) {} +//! # pub fn on(&mut self) {} +//! # } +//! # } +//! ``` +//! +//! ## Generic programming and higher level abstractions +//! +//! The core of the HAL has been kept minimal on purpose to encourage building **generic** higher +//! level abstractions on top of it. Some higher level abstractions that pick an asynchronous model +//! or that have blocking behavior and that are deemed useful to build other abstractions can be +//! found in the `blocking` module and, in the future, in the `futures` and `async` modules. +//! +//! Some examples: +//! +//! **NOTE** All the functions shown below could have been written as trait +//! methods with default implementation to allow specialization, but they have +//! been written as functions to keep things simple. +//! +//! - Write a whole buffer to a serial device in blocking a fashion. +//! +//! ``` +//! extern crate embedded_hal as hal; +//! #[macro_use(block)] +//! extern crate nb; +//! +//! use hal::prelude::*; +//! +//! fn write_all(serial: &mut S, buffer: &[u8]) -> Result<(), S::Error> +//! where +//! S: hal::serial::Write +//! { +//! for &byte in buffer { +//! block!(serial.write(byte))?; +//! } +//! +//! Ok(()) +//! } +//! +//! # fn main() {} +//! ``` +//! +//! - Blocking serial read with timeout +//! +//! ``` +//! extern crate embedded_hal as hal; +//! extern crate nb; +//! +//! use hal::prelude::*; +//! +//! enum Error { +//! /// Serial interface error +//! Serial(E), +//! TimedOut, +//! } +//! +//! fn read_with_timeout( +//! serial: &mut S, +//! timer: &mut T, +//! timeout: T::Time, +//! ) -> Result> +//! where +//! T: hal::timer::CountDown, +//! S: hal::serial::Read, +//! { +//! timer.start(timeout); +//! +//! loop { +//! match serial.read() { +//! // raise error +//! Err(nb::Error::Other(e)) => return Err(Error::Serial(e)), +//! Err(nb::Error::WouldBlock) => { +//! // no data available yet, check the timer below +//! }, +//! Ok(byte) => return Ok(byte), +//! } +//! +//! match timer.wait() { +//! Err(nb::Error::Other(e)) => { +//! // The error type specified by `timer.wait()` is `!`, which +//! // means no error can actually occur. The Rust compiler +//! // still forces us to provide this match arm, though. +//! unreachable!() +//! }, +//! // no timeout yet, try again +//! Err(nb::Error::WouldBlock) => continue, +//! Ok(()) => return Err(Error::TimedOut), +//! } +//! } +//! } +//! +//! # fn main() {} +//! ``` +//! +//! - Asynchronous SPI transfer +//! +//! ``` +//! #![feature(conservative_impl_trait)] +//! #![feature(generators)] +//! #![feature(generator_trait)] +//! +//! extern crate embedded_hal as hal; +//! #[macro_use(await)] +//! extern crate nb; +//! +//! use std::ops::Generator; +//! +//! /// Transfers a byte buffer of size N +//! /// +//! /// Returns the same byte buffer but filled with the data received from the +//! /// slave device +//! fn transfer( +//! mut spi: S, +//! mut buffer: [u8; 16], // NOTE this should be generic over the size of the array +//! ) -> impl Generator, Yield = ()> +//! where +//! S: hal::spi::FullDuplex, +//! { +//! move || { +//! let n = buffer.len(); +//! for i in 0..n { +//! await!(spi.send(buffer[i]))?; +//! buffer[i] = await!(spi.read())?; +//! } +//! +//! Ok((spi, buffer)) +//! } +//! } +//! +//! # fn main() {} +//! ``` +//! +//! - Buffered serial interface with periodic flushing in interrupt handler +//! +//! ``` +//! extern crate embedded_hal as hal; +//! extern crate nb; +//! extern crate void; +//! +//! use hal::prelude::*; +//! use void::Void; +//! +//! fn flush(serial: &mut S, cb: &mut CircularBuffer) +//! where +//! S: hal::serial::Write, +//! { +//! loop { +//! if let Some(byte) = cb.peek() { +//! match serial.write(*byte) { +//! Err(nb::Error::Other(_)) => unreachable!(), +//! Err(nb::Error::WouldBlock) => return, +//! Ok(()) => {}, // keep flushing data +//! } +//! } +//! +//! cb.pop(); +//! } +//! } +//! +//! // The stuff below could be in some other crate +//! +//! /// Global singleton +//! pub struct BufferedSerial1; +//! +//! // NOTE private +//! static BUFFER1: Mutex = { +//! // .. +//! # Mutex(CircularBuffer) +//! }; +//! static SERIAL1: Mutex = { +//! // .. +//! # Mutex(Serial1) +//! }; +//! +//! impl BufferedSerial1 { +//! pub fn write(&self, byte: u8) { +//! self.write_all(&[byte]) +//! } +//! +//! pub fn write_all(&self, bytes: &[u8]) { +//! let mut buffer = BUFFER1.lock(); +//! for byte in bytes { +//! buffer.push(*byte).expect("buffer overrun"); +//! } +//! // omitted: pend / enable interrupt_handler +//! } +//! } +//! +//! fn interrupt_handler() { +//! let mut serial = SERIAL1.lock(); +//! let mut buffer = BUFFER1.lock(); +//! +//! flush(&mut *serial, &mut buffer); +//! } +//! +//! # struct Mutex(T); +//! # impl Mutex { +//! # fn lock(&self) -> RefMut { unimplemented!() } +//! # } +//! # struct RefMut<'a, T>(&'a mut T) where T: 'a; +//! # impl<'a, T> ::std::ops::Deref for RefMut<'a, T> { +//! # type Target = T; +//! # fn deref(&self) -> &T { self.0 } +//! # } +//! # impl<'a, T> ::std::ops::DerefMut for RefMut<'a, T> { +//! # fn deref_mut(&mut self) -> &mut T { self.0 } +//! # } +//! # struct Serial1; +//! # impl ::hal::serial::Write for Serial1 { +//! # type Error = Void; +//! # fn write(&mut self, _: u8) -> nb::Result<(), Void> { Err(::nb::Error::WouldBlock) } +//! # fn flush(&mut self) -> nb::Result<(), Void> { Err(::nb::Error::WouldBlock) } +//! # } +//! # struct CircularBuffer; +//! # impl CircularBuffer { +//! # pub fn peek(&mut self) -> Option<&u8> { None } +//! # pub fn pop(&mut self) -> Option { None } +//! # pub fn push(&mut self, _: u8) -> Result<(), ()> { Ok(()) } +//! # } +//! +//! # fn main() {} +//! ``` + +#![deny(missing_docs)] +#![no_std] + +#[macro_use] +extern crate nb; +extern crate void; + +pub mod adc; +pub mod blocking; +pub mod can; +pub mod digital; +pub mod fmt; +pub mod prelude; +pub mod serial; +pub mod spi; +pub mod timer; +pub mod watchdog; + +/// Input capture +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// # Examples +/// +/// You can use this interface to measure the period of (quasi) periodic signals +/// / events +/// +/// ``` +/// extern crate embedded_hal as hal; +/// #[macro_use(block)] +/// extern crate nb; +/// +/// use hal::prelude::*; +/// +/// fn main() { +/// let mut capture: Capture1 = { +/// // .. +/// # Capture1 +/// }; +/// +/// capture.set_resolution(1.ms()); +/// +/// let before = block!(capture.capture(Channel::_1)).unwrap(); +/// let after = block!(capture.capture(Channel::_1)).unwrap(); +/// +/// let period = after.wrapping_sub(before); +/// +/// println!("Period: {} ms", period); +/// } +/// +/// # extern crate void; +/// # use void::Void; +/// # struct MilliSeconds(u32); +/// # trait U32Ext { fn ms(self) -> MilliSeconds; } +/// # impl U32Ext for u32 { fn ms(self) -> MilliSeconds { MilliSeconds(self) } } +/// # struct Capture1; +/// # enum Channel { _1 } +/// # impl hal::Capture for Capture1 { +/// # type Capture = u16; +/// # type Channel = Channel; +/// # type Error = Void; +/// # type Time = MilliSeconds; +/// # fn capture(&mut self, _: Channel) -> ::nb::Result { Ok(0) } +/// # fn disable(&mut self, _: Channel) { unimplemented!() } +/// # fn enable(&mut self, _: Channel) { unimplemented!() } +/// # fn get_resolution(&self) -> MilliSeconds { unimplemented!() } +/// # fn set_resolution(&mut self, _: T) where T: Into {} +/// # } +/// ``` +#[cfg(feature = "unproven")] +// reason: pre-singletons API. With singletons a `CapturePin` (cf. `PwmPin`) trait seems more +// appropriate +pub trait Capture { + /// Enumeration of `Capture` errors + /// + /// Possible errors: + /// + /// - *overcapture*, the previous capture value was overwritten because it + /// was not read in a timely manner + type Error; + + /// Enumeration of channels that can be used with this `Capture` interface + /// + /// If your `Capture` interface has no channels you can use the type `()` + /// here + type Channel; + + /// A time unit that can be converted into a human time unit (e.g. seconds) + type Time; + + /// The type of the value returned by `capture` + type Capture; + + /// "Waits" for a transition in the capture `channel` and returns the value + /// of counter at that instant + /// + /// NOTE that you must multiply the returned value by the *resolution* of + /// this `Capture` interface to get a human time unit (e.g. seconds) + fn capture(&mut self, channel: Self::Channel) -> nb::Result; + + /// Disables a capture `channel` + fn disable(&mut self, channel: Self::Channel); + + /// Enables a capture `channel` + fn enable(&mut self, channel: Self::Channel); + + /// Returns the current resolution + fn get_resolution(&self) -> Self::Time; + + /// Sets the resolution of the capture timer + fn set_resolution(&mut self, resolution: R) + where + R: Into; +} + +/// Pulse Width Modulation +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// # Examples +/// +/// Use this interface to control the power output of some actuator +/// +/// ``` +/// extern crate embedded_hal as hal; +/// +/// use hal::prelude::*; +/// +/// fn main() { +/// let mut pwm: Pwm1 = { +/// // .. +/// # Pwm1 +/// }; +/// +/// pwm.set_period(1.khz()); +/// +/// let max_duty = pwm.get_max_duty(); +/// +/// // brightest LED +/// pwm.set_duty(Channel::_1, max_duty); +/// +/// // dimmer LED +/// pwm.set_duty(Channel::_2, max_duty / 4); +/// } +/// +/// # struct KiloHertz(u32); +/// # trait U32Ext { fn khz(self) -> KiloHertz; } +/// # impl U32Ext for u32 { fn khz(self) -> KiloHertz { KiloHertz(self) } } +/// # enum Channel { _1, _2 } +/// # struct Pwm1; +/// # impl hal::Pwm for Pwm1 { +/// # type Channel = Channel; +/// # type Time = KiloHertz; +/// # type Duty = u16; +/// # fn disable(&mut self, _: Channel) { unimplemented!() } +/// # fn enable(&mut self, _: Channel) { unimplemented!() } +/// # fn get_duty(&self, _: Channel) -> u16 { unimplemented!() } +/// # fn get_max_duty(&self) -> u16 { 0 } +/// # fn set_duty(&mut self, _: Channel, _: u16) {} +/// # fn get_period(&self) -> KiloHertz { unimplemented!() } +/// # fn set_period(&mut self, _: T) where T: Into {} +/// # } +/// ``` +#[cfg(feature = "unproven")] +// reason: pre-singletons API. The `PwmPin` trait seems more useful because it models independent +// PWM channels. Here a certain number of channels are multiplexed in a single implementer. +pub trait Pwm { + /// Enumeration of channels that can be used with this `Pwm` interface + /// + /// If your `Pwm` interface has no channels you can use the type `()` + /// here + type Channel; + + /// A time unit that can be converted into a human time unit (e.g. seconds) + type Time; + + /// Type for the `duty` methods + /// + /// The implementer is free to choose a float / percentage representation + /// (e.g. `0.0 .. 1.0`) or an integer representation (e.g. `0 .. 65535`) + type Duty; + + /// Disables a PWM `channel` + fn disable(&mut self, channel: Self::Channel); + + /// Enables a PWM `channel` + fn enable(&mut self, channel: Self::Channel); + + /// Returns the current PWM period + fn get_period(&self) -> Self::Time; + + /// Returns the current duty cycle + fn get_duty(&self, channel: Self::Channel) -> Self::Duty; + + /// Returns the maximum duty cycle value + fn get_max_duty(&self) -> Self::Duty; + + /// Sets a new duty cycle + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty); + + /// Sets a new PWM period + fn set_period

(&mut self, period: P) + where + P: Into; +} + +/// A single PWM channel / pin +/// +/// See `Pwm` for details +pub trait PwmPin { + /// Type for the `duty` methods + /// + /// The implementer is free to choose a float / percentage representation + /// (e.g. `0.0 .. 1.0`) or an integer representation (e.g. `0 .. 65535`) + type Duty; + + /// Disables a PWM `channel` + fn disable(&mut self); + + /// Enables a PWM `channel` + fn enable(&mut self); + + /// Returns the current duty cycle + fn get_duty(&self) -> Self::Duty; + + /// Returns the maximum duty cycle value + fn get_max_duty(&self) -> Self::Duty; + + /// Sets a new duty cycle + fn set_duty(&mut self, duty: Self::Duty); +} + +/// Quadrature encoder interface +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +/// +/// # Examples +/// +/// You can use this interface to measure the speed of a motor +/// +/// ``` +/// extern crate embedded_hal as hal; +/// #[macro_use(block)] +/// extern crate nb; +/// +/// use hal::prelude::*; +/// +/// fn main() { +/// let mut qei: Qei1 = { +/// // .. +/// # Qei1 +/// }; +/// let mut timer: Timer6 = { +/// // .. +/// # Timer6 +/// }; +/// +/// +/// let before = qei.count(); +/// timer.start(1.s()); +/// block!(timer.wait()); +/// let after = qei.count(); +/// +/// let speed = after.wrapping_sub(before); +/// println!("Speed: {} pulses per second", speed); +/// } +/// +/// # extern crate void; +/// # use void::Void; +/// # struct Seconds(u32); +/// # trait U32Ext { fn s(self) -> Seconds; } +/// # impl U32Ext for u32 { fn s(self) -> Seconds { Seconds(self) } } +/// # struct Qei1; +/// # impl hal::Qei for Qei1 { +/// # type Count = u16; +/// # fn count(&self) -> u16 { 0 } +/// # fn direction(&self) -> ::hal::Direction { unimplemented!() } +/// # } +/// # struct Timer6; +/// # impl hal::timer::CountDown for Timer6 { +/// # type Time = Seconds; +/// # fn start(&mut self, _: T) where T: Into {} +/// # fn wait(&mut self) -> ::nb::Result<(), Void> { Ok(()) } +/// # } +/// ``` +#[cfg(feature = "unproven")] +// reason: needs to be re-evaluated in the new singletons world. At the very least this needs a +// reference implementation +pub trait Qei { + /// The type of the value returned by `count` + type Count; + + /// Returns the current pulse count of the encoder + fn count(&self) -> Self::Count; + + /// Returns the count direction + fn direction(&self) -> Direction; +} + +/// Count direction +/// +/// *This enumeration is available if embedded-hal is built with the `"unproven"` feature.* +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg(feature = "unproven")] +// reason: part of the unproven `Qei` interface +pub enum Direction { + /// 3, 2, 1 + Downcounting, + /// 1, 2, 3 + Upcounting, +} + +mod private { + pub trait Sealed {} +} diff --git a/src/rust/vendor/embedded-hal/src/prelude.rs b/src/rust/vendor/embedded-hal/src/prelude.rs new file mode 100644 index 000000000..4d17043ad --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/prelude.rs @@ -0,0 +1,44 @@ +//! The prelude is a collection of all the traits in this crate +//! +//! The traits have been renamed to avoid collisions with other items when +//! performing a glob import. + +#[cfg(feature = "unproven")] +pub use adc::OneShot as _embedded_hal_adc_OneShot; +pub use blocking::delay::DelayMs as _embedded_hal_blocking_delay_DelayMs; +pub use blocking::delay::DelayUs as _embedded_hal_blocking_delay_DelayUs; +pub use blocking::i2c::{ + Read as _embedded_hal_blocking_i2c_Read, Write as _embedded_hal_blocking_i2c_Write, + WriteRead as _embedded_hal_blocking_i2c_WriteRead, +}; +#[cfg(feature = "unproven")] +pub use blocking::rng::Read as _embedded_hal_blocking_rng_Read; +pub use blocking::serial::Write as _embedded_hal_blocking_serial_Write; +pub use blocking::spi::{ + Transfer as _embedded_hal_blocking_spi_Transfer, Write as _embedded_hal_blocking_spi_Write, +}; +#[allow(deprecated)] +#[cfg(feature = "unproven")] +pub use digital::InputPin as _embedded_hal_digital_InputPin; +#[allow(deprecated)] +pub use digital::OutputPin as _embedded_hal_digital_OutputPin; +#[cfg(feature = "unproven")] +#[allow(deprecated)] +pub use digital::ToggleableOutputPin as _embedded_hal_digital_ToggleableOutputPin; +pub use serial::Read as _embedded_hal_serial_Read; +pub use serial::Write as _embedded_hal_serial_Write; +pub use spi::FullDuplex as _embedded_hal_spi_FullDuplex; +pub use timer::CountDown as _embedded_hal_timer_CountDown; +#[cfg(feature = "unproven")] +pub use watchdog::Watchdog as _embedded_hal_watchdog_Watchdog; +#[cfg(feature = "unproven")] +pub use watchdog::WatchdogDisable as _embedded_hal_watchdog_WatchdogDisable; +#[cfg(feature = "unproven")] +pub use watchdog::WatchdogEnable as _embedded_hal_watchdog_WatchdogEnable; +#[cfg(feature = "unproven")] +pub use Capture as _embedded_hal_Capture; +#[cfg(feature = "unproven")] +pub use Pwm as _embedded_hal_Pwm; +pub use PwmPin as _embedded_hal_PwmPin; +#[cfg(feature = "unproven")] +pub use Qei as _embedded_hal_Qei; diff --git a/src/rust/vendor/embedded-hal/src/serial.rs b/src/rust/vendor/embedded-hal/src/serial.rs new file mode 100644 index 000000000..484bb2967 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/serial.rs @@ -0,0 +1,27 @@ +//! Serial interface + +use nb; + +/// Read half of a serial interface +/// +/// Some serial interfaces support different data sizes (8 bits, 9 bits, etc.); +/// This can be encoded in this trait via the `Word` type parameter. +pub trait Read { + /// Read error + type Error; + + /// Reads a single word from the serial interface + fn read(&mut self) -> nb::Result; +} + +/// Write half of a serial interface +pub trait Write { + /// Write error + type Error; + + /// Writes a single word to the serial interface + fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>; + + /// Ensures that none of the previously written words are still buffered + fn flush(&mut self) -> nb::Result<(), Self::Error>; +} diff --git a/src/rust/vendor/embedded-hal/src/spi.rs b/src/rust/vendor/embedded-hal/src/spi.rs new file mode 100644 index 000000000..20d8538cd --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/spi.rs @@ -0,0 +1,78 @@ +//! Serial Peripheral Interface + +use nb; + +/// Full duplex (master mode) +/// +/// # Notes +/// +/// - It's the task of the user of this interface to manage the slave select lines +/// +/// - Due to how full duplex SPI works each `read` call must be preceded by a `send` call. +/// +/// - Some SPIs can work with 8-bit *and* 16-bit words. You can overload this trait with different +/// `Word` types to allow operation in both modes. +pub trait FullDuplex { + /// An enumeration of SPI errors + type Error; + + /// Reads the word stored in the shift register + /// + /// **NOTE** A word must be sent to the slave before attempting to call this + /// method. + fn read(&mut self) -> nb::Result; + + /// Sends a word to the slave + fn send(&mut self, word: Word) -> nb::Result<(), Self::Error>; +} + +/// Clock polarity +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Polarity { + /// Clock signal low when idle + IdleLow, + /// Clock signal high when idle + IdleHigh, +} + +/// Clock phase +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Phase { + /// Data in "captured" on the first clock transition + CaptureOnFirstTransition, + /// Data in "captured" on the second clock transition + CaptureOnSecondTransition, +} + +/// SPI mode +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Mode { + /// Clock polarity + pub polarity: Polarity, + /// Clock phase + pub phase: Phase, +} + +/// Helper for CPOL = 0, CPHA = 0 +pub const MODE_0: Mode = Mode { + polarity: Polarity::IdleLow, + phase: Phase::CaptureOnFirstTransition, +}; + +/// Helper for CPOL = 0, CPHA = 1 +pub const MODE_1: Mode = Mode { + polarity: Polarity::IdleLow, + phase: Phase::CaptureOnSecondTransition, +}; + +/// Helper for CPOL = 1, CPHA = 0 +pub const MODE_2: Mode = Mode { + polarity: Polarity::IdleHigh, + phase: Phase::CaptureOnFirstTransition, +}; + +/// Helper for CPOL = 1, CPHA = 1 +pub const MODE_3: Mode = Mode { + polarity: Polarity::IdleHigh, + phase: Phase::CaptureOnSecondTransition, +}; diff --git a/src/rust/vendor/embedded-hal/src/timer.rs b/src/rust/vendor/embedded-hal/src/timer.rs new file mode 100644 index 000000000..08ba27606 --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/timer.rs @@ -0,0 +1,95 @@ +//! Timers + +use nb; +use void::Void; + +/// A count down timer +/// +/// # Contract +/// +/// - `self.start(count); block!(self.wait());` MUST block for AT LEAST the time specified by +/// `count`. +/// +/// *Note* that the implementer doesn't necessarily have to be a *downcounting* timer; it could also +/// be an *upcounting* timer as long as the above contract is upheld. +/// +/// # Examples +/// +/// You can use this timer to create delays +/// +/// ``` +/// extern crate embedded_hal as hal; +/// #[macro_use(block)] +/// extern crate nb; +/// +/// use hal::prelude::*; +/// +/// fn main() { +/// let mut led: Led = { +/// // .. +/// # Led +/// }; +/// let mut timer: Timer6 = { +/// // .. +/// # Timer6 +/// }; +/// +/// Led.on(); +/// timer.start(1.s()); +/// block!(timer.wait()); // blocks for 1 second +/// Led.off(); +/// } +/// +/// # extern crate void; +/// # use void::Void; +/// # struct Seconds(u32); +/// # trait U32Ext { fn s(self) -> Seconds; } +/// # impl U32Ext for u32 { fn s(self) -> Seconds { Seconds(self) } } +/// # struct Led; +/// # impl Led { +/// # pub fn off(&mut self) {} +/// # pub fn on(&mut self) {} +/// # } +/// # struct Timer6; +/// # impl hal::timer::CountDown for Timer6 { +/// # type Time = Seconds; +/// # fn start(&mut self, _: T) where T: Into {} +/// # fn wait(&mut self) -> ::nb::Result<(), Void> { Ok(()) } +/// # } +/// ``` +pub trait CountDown { + /// The unit of time used by this timer + type Time; + + /// Starts a new count down + fn start(&mut self, count: T) + where + T: Into; + + /// Non-blockingly "waits" until the count down finishes + /// + /// # Contract + /// + /// - If `Self: Periodic`, the timer will start a new count down right after the last one + /// finishes. + /// - Otherwise the behavior of calling `wait` after the last call returned `Ok` is UNSPECIFIED. + /// Implementers are suggested to panic on this scenario to signal a programmer error. + fn wait(&mut self) -> nb::Result<(), Void>; +} + +/// Marker trait that indicates that a timer is periodic +pub trait Periodic {} + +/// Trait for cancelable countdowns. +pub trait Cancel: CountDown { + /// Error returned when a countdown can't be canceled. + type Error; + + /// Tries to cancel this countdown. + /// + /// # Errors + /// + /// An error will be returned if the countdown has already been canceled or was never started. + /// An error is also returned if the countdown is not `Periodic` and has already expired. + fn cancel(&mut self) -> Result<(), Self::Error>; +} diff --git a/src/rust/vendor/embedded-hal/src/watchdog.rs b/src/rust/vendor/embedded-hal/src/watchdog.rs new file mode 100644 index 000000000..41e76f6ba --- /dev/null +++ b/src/rust/vendor/embedded-hal/src/watchdog.rs @@ -0,0 +1,30 @@ +//! Traits for interactions with a processors watchdog timer. + +/// Feeds an existing watchdog to ensure the processor isn't reset. Sometimes +/// commonly referred to as "kicking" or "refreshing". +#[cfg(feature = "unproven")] +pub trait Watchdog { + /// Triggers the watchdog. This must be done once the watchdog is started + /// to prevent the processor being reset. + fn feed(&mut self); +} + +/// Enables A watchdog timer to reset the processor if software is frozen or +/// stalled. +#[cfg(feature = "unproven")] +pub trait WatchdogEnable { + /// Unit of time used by the watchdog + type Time; + /// Starts the watchdog with a given period, typically once this is done + /// the watchdog needs to be kicked periodically or the processor is reset. + fn start(&mut self, period: T) + where + T: Into; +} + +/// Disables a running watchdog timer so the processor won't be reset. +#[cfg(feature = "unproven")] +pub trait WatchdogDisable { + /// Disables the watchdog + fn disable(&mut self); +} diff --git a/src/rust/vendor/nb-0.1.3/.cargo-checksum.json b/src/rust/vendor/nb-0.1.3/.cargo-checksum.json new file mode 100644 index 000000000..39a1a4a3e --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"6656d9902a33a76e1f57ae269cc4290a20f0660b7098451f0222d6a2e05211a6","Cargo.toml":"f277cf77fc1263e49054d92acb079e11bb747b1a310a66d262f9824c7ebaf573","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"035e70219855119df4273b3c5b97543ae82e0dd60c520416e759107c602f651b","README.md":"f58c64d699a84555e9542fad4acf71d3f4fb6bc266199efa9dde7d999ece9263","bors.toml":"b96eaac6b3dc8487a2bcc6cb415e745a28d9a61937090df48186c62d2b614aeb","src/lib.rs":"7dc2ec005f5307821c792536841c9db8285614ebff5471fc029de8300d410008"},"package":"801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"} \ No newline at end of file diff --git a/src/rust/vendor/nb-0.1.3/CHANGELOG.md b/src/rust/vendor/nb-0.1.3/CHANGELOG.md new file mode 100644 index 000000000..23feb8763 --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/CHANGELOG.md @@ -0,0 +1,37 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.1.3] - 2020-07-07 + +This release of the 0.1 version exists for compatibility with 1.0.0. +There are no functional changes compared to 0.1.2. + +## [v0.1.2] - 2019-04-21 + +### Added + +- `Error` gained a `map` method that lets you transform the error in the + `Error::Other` variant into a different type. + +- `Error` now implements the `From` trait. + +## [v0.1.1] - 2018-01-10 + +### Fixed + +- The `await!` macro now works when the expression `$e` mutably borrows `self`. + +## v0.1.0 - 2018-01-10 + +Initial release + +[Unreleased]: https://github.com/rust-embedded/nb/compare/v0.1.3...HEAD +[v0.1.3]: https://github.com/rust-embedded/nb/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/rust-embedded/nb/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-embedded/nb/compare/v0.1.0...v0.1.1 diff --git a/src/rust/vendor/nb-0.1.3/Cargo.toml b/src/rust/vendor/nb-0.1.3/Cargo.toml new file mode 100644 index 000000000..983933b05 --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "nb" +version = "0.1.3" +authors = ["Jorge Aparicio "] +description = "Minimal non-blocking I/O layer" +homepage = "https://github.com/rust-embedded/nb" +documentation = "https://docs.rs/nb" +readme = "README.md" +keywords = ["await", "futures", "IO"] +categories = ["asynchronous", "embedded", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-embedded/nb" + +[lib] +doctest = false +[dependencies.nb] +version = "1" +[dev-dependencies.futures] +version = "0.1.17" + +[features] +unstable = [] diff --git a/src/rust/vendor/nb-0.1.3/LICENSE-APACHE b/src/rust/vendor/nb-0.1.3/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/nb-0.1.3/LICENSE-MIT b/src/rust/vendor/nb-0.1.3/LICENSE-MIT new file mode 100644 index 000000000..a128ba402 --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/nb-0.1.3/README.md b/src/rust/vendor/nb-0.1.3/README.md new file mode 100644 index 000000000..13ec08d77 --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/README.md @@ -0,0 +1,25 @@ +# `nb` + +> Minimal and reusable non-blocking I/O layer + +This project is developed and maintained by the [HAL team][team]. + +## [Documentation](https://docs.rs/nb) + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[team]: https://github.com/rust-embedded/wg#the-hal-team diff --git a/src/rust/vendor/nb-0.1.3/bors.toml b/src/rust/vendor/nb-0.1.3/bors.toml new file mode 100644 index 000000000..5ccee21e0 --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/bors.toml @@ -0,0 +1,3 @@ +status = [ + "continuous-integration/travis-ci/push", +] \ No newline at end of file diff --git a/src/rust/vendor/nb-0.1.3/src/lib.rs b/src/rust/vendor/nb-0.1.3/src/lib.rs new file mode 100644 index 000000000..a1f534f18 --- /dev/null +++ b/src/rust/vendor/nb-0.1.3/src/lib.rs @@ -0,0 +1,438 @@ +//! Minimal and reusable non-blocking I/O layer +//! +//! The ultimate goal of this crate is *code reuse*. With this crate you can +//! write *core* I/O APIs that can then be adapted to operate in either blocking +//! or non-blocking manner. Furthermore those APIs are not tied to a particular +//! asynchronous model and can be adapted to work with the `futures` model or +//! with the `async` / `await` model. +//! +//! # Core idea +//! +//! The [`WouldBlock`](enum.Error.html) error variant signals that the operation +//! can't be completed *right now* and would need to block to complete. +//! [`WouldBlock`](enum.Error.html) is a special error in the sense that's not +//! *fatal*; the operation can still be completed by retrying again later. +//! +//! [`nb::Result`](type.Result.html) is based on the API of +//! [`std::io::Result`](https://doc.rust-lang.org/std/io/type.Result.html), +//! which has a `WouldBlock` variant in its +//! [`ErrorKind`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html). +//! +//! We can map [`WouldBlock`](enum.Error.html) to different blocking and +//! non-blocking models: +//! +//! - In blocking mode: [`WouldBlock`](enum.Error.html) means try again right +//! now (i.e. busy wait) +//! - In `futures` mode: [`WouldBlock`](enum.Error.html) means +//! [`Async::NotReady`](https://docs.rs/futures) +//! - In `await` mode: [`WouldBlock`](enum.Error.html) means `yield` +//! (suspend the generator) +//! +//! # How to use this crate +//! +//! Application specific errors can be put inside the `Other` variant in the +//! [`nb::Error`](enum.Error.html) enum. +//! +//! So in your API instead of returning `Result` return +//! `nb::Result` +//! +//! ``` +//! enum MyError { +//! ThisError, +//! ThatError, +//! // .. +//! } +//! +//! // This is a blocking function, so it returns a normal `Result` +//! fn before() -> Result<(), MyError> { +//! // .. +//! # Ok(()) +//! } +//! +//! // This is now a potentially (read: *non*) blocking function so it returns `nb::Result` +//! // instead of blocking +//! fn after() -> nb::Result<(), MyError> { +//! // .. +//! # Ok(()) +//! } +//! ``` +//! +//! You can use the *never type* (`!`) to signal that some API has no fatal +//! errors but may block: +//! +//! ``` +//! #![feature(never_type)] +//! +//! // This returns `Ok(())` or `Err(nb::Error::WouldBlock)` +//! fn maybe_blocking_api() -> nb::Result<(), !> { +//! // .. +//! # Ok(()) +//! } +//! ``` +//! +//! Once your API uses [`nb::Result`](type.Result.html) you can leverage the +//! [`block!`], [`try_nb!`] and [`await!`] macros to adapt it for blocking +//! operation, or for non-blocking operation with `futures` or `await`. +//! +//! **NOTE** Currently, both `try_nb!` and `await!` are feature gated behind the `unstable` Cargo +//! feature. +//! +//! [`block!`]: macro.block.html +//! [`try_nb!`]: macro.try_nb.html +//! [`await!`]: macro.await.html +//! +//! # Examples +//! +//! ## A Core I/O API +//! +//! Imagine the code (crate) below represents a Hardware Abstraction Layer for some microcontroller +//! (or microcontroller family). +//! +//! *In this and the following examples let's assume for simplicity that peripherals are treated +//! as global singletons and that no preemption is possible (i.e. interrupts are disabled).* +//! +//! ``` +//! #![feature(never_type)] +//! +//! // This is the `hal` crate +//! // Note that it doesn't depend on the `futures` crate +//! +//! extern crate nb; +//! +//! /// An LED +//! pub struct Led; +//! +//! impl Led { +//! pub fn off(&self) { +//! // .. +//! } +//! pub fn on(&self) { +//! // .. +//! } +//! } +//! +//! /// Serial interface +//! pub struct Serial; +//! pub enum Error { +//! Overrun, +//! // .. +//! } +//! +//! impl Serial { +//! /// Reads a single byte from the serial interface +//! pub fn read(&self) -> nb::Result { +//! // .. +//! # Ok(0) +//! } +//! +//! /// Writes a single byte to the serial interface +//! pub fn write(&self, byte: u8) -> nb::Result<(), Error> { +//! // .. +//! # Ok(()) +//! } +//! } +//! +//! /// A timer used for timeouts +//! pub struct Timer; +//! +//! impl Timer { +//! /// Waits until the timer times out +//! pub fn wait(&self) -> nb::Result<(), !> { +//! //^ NOTE the `!` indicates that this operation can block but has no +//! // other form of error +//! +//! // .. +//! # Ok(()) +//! } +//! } +//! ``` +//! +//! ## Blocking mode +//! +//! Turn on an LED for one second and *then* loops back serial data. +//! +//! ``` +//! # #![feature(never_type)] +//! #[macro_use(block)] +//! extern crate nb; +//! +//! use hal::{Led, Serial, Timer}; +//! +//! fn main() { +//! // Turn the LED on for one second +//! Led.on(); +//! block!(Timer.wait()).unwrap(); // NOTE(unwrap) E = ! +//! Led.off(); +//! +//! // Serial interface loopback +//! # return; +//! loop { +//! let byte = block!(Serial.read()).unwrap(); +//! block!(Serial.write(byte)).unwrap(); +//! } +//! } +//! +//! # mod hal { +//! # use nb; +//! # pub struct Led; +//! # impl Led { +//! # pub fn off(&self) {} +//! # pub fn on(&self) {} +//! # } +//! # pub struct Serial; +//! # impl Serial { +//! # pub fn read(&self) -> nb::Result { Ok(0) } +//! # pub fn write(&self, _: u8) -> nb::Result<(), ()> { Ok(()) } +//! # } +//! # pub struct Timer; +//! # impl Timer { +//! # pub fn wait(&self) -> nb::Result<(), !> { Ok(()) } +//! # } +//! # } +//! ``` +//! +//! ## `futures` +//! +//! Blinks an LED every second *and* loops back serial data. Both tasks run +//! concurrently. +//! +//! ``` +//! #![feature(conservative_impl_trait)] +//! #![feature(never_type)] +//! +//! extern crate futures; +//! #[macro_use(try_nb)] +//! extern crate nb; +//! +//! use futures::{Async, Future}; +//! use futures::future::{self, Loop}; +//! use hal::{Error, Led, Serial, Timer}; +//! +//! /// `futures` version of `Timer.wait` +//! /// +//! /// This returns a future that must be polled to completion +//! fn wait() -> impl Future { +//! future::poll_fn(|| { +//! Ok(Async::Ready(try_nb!(Timer.wait()))) +//! }) +//! } +//! +//! /// `futures` version of `Serial.read` +//! /// +//! /// This returns a future that must be polled to completion +//! fn read() -> impl Future { +//! future::poll_fn(|| { +//! Ok(Async::Ready(try_nb!(Serial.read()))) +//! }) +//! } +//! +//! /// `futures` version of `Serial.write` +//! /// +//! /// This returns a future that must be polled to completion +//! fn write(byte: u8) -> impl Future { +//! future::poll_fn(move || { +//! Ok(Async::Ready(try_nb!(Serial.write(byte)))) +//! }) +//! } +//! +//! fn main() { +//! // Tasks +//! let mut blinky = future::loop_fn::<_, (), _, _>(true, |state| { +//! wait().map(move |_| { +//! if state { +//! Led.on(); +//! } else { +//! Led.off(); +//! } +//! +//! Loop::Continue(!state) +//! }) +//! }); +//! +//! let mut loopback = future::loop_fn::<_, (), _, _>((), |_| { +//! read().and_then(|byte| { +//! write(byte) +//! }).map(|_| { +//! Loop::Continue(()) +//! }) +//! }); +//! +//! // Event loop +//! loop { +//! blinky.poll().unwrap(); // NOTE(unwrap) E = ! +//! loopback.poll().unwrap(); +//! # break +//! } +//! } +//! +//! # mod hal { +//! # use nb; +//! # pub struct Led; +//! # impl Led { +//! # pub fn off(&self) {panic!()} +//! # pub fn on(&self) {} +//! # } +//! # #[derive(Debug)] +//! # pub enum Error {} +//! # pub struct Serial; +//! # impl Serial { +//! # pub fn read(&self) -> nb::Result { Err(nb::Error::WouldBlock) } +//! # pub fn write(&self, _: u8) -> nb::Result<(), Error> { Err(nb::Error::WouldBlock) } +//! # } +//! # pub struct Timer; +//! # impl Timer { +//! # pub fn wait(&self) -> nb::Result<(), !> { Err(nb::Error::WouldBlock) } +//! # } +//! # } +//! ``` +//! +//! ## `await!` +//! +//! This is equivalent to the `futures` example but with much less boilerplate. +//! +//! ``` +//! #![feature(generator_trait)] +//! #![feature(generators)] +//! #![feature(never_type)] +//! +//! #[macro_use(await)] +//! extern crate nb; +//! +//! use std::ops::Generator; +//! +//! use hal::{Led, Serial, Timer}; +//! +//! fn main() { +//! // Tasks +//! let mut blinky = || { +//! let mut state = false; +//! loop { +//! // `await!` means suspend / yield instead of blocking +//! await!(Timer.wait()).unwrap(); // NOTE(unwrap) E = ! +//! +//! state = !state; +//! +//! if state { +//! Led.on(); +//! } else { +//! Led.off(); +//! } +//! } +//! }; +//! +//! let mut loopback = || { +//! loop { +//! let byte = await!(Serial.read()).unwrap(); +//! await!(Serial.write(byte)).unwrap(); +//! } +//! }; +//! +//! // Event loop +//! loop { +//! blinky.resume(); +//! loopback.resume(); +//! # break +//! } +//! } +//! +//! # mod hal { +//! # use nb; +//! # pub struct Led; +//! # impl Led { +//! # pub fn off(&self) {} +//! # pub fn on(&self) {} +//! # } +//! # pub struct Serial; +//! # impl Serial { +//! # pub fn read(&self) -> nb::Result { Err(nb::Error::WouldBlock) } +//! # pub fn write(&self, _: u8) -> nb::Result<(), ()> { Err(nb::Error::WouldBlock) } +//! # } +//! # pub struct Timer; +//! # impl Timer { +//! # pub fn wait(&self) -> nb::Result<(), !> { Err(nb::Error::WouldBlock) } +//! # } +//! # } +//! ``` + +#![no_std] +#![doc(html_root_url = "https://docs.rs/nb/0.1.3")] + +extern crate nb; +pub use nb::{block, Error, Result}; + +/// Await operation (*won't work until the language gains support for +/// generators*) +/// +/// This macro evaluates the expression `$e` *cooperatively* yielding control +/// back to the (generator) caller whenever `$e` evaluates to +/// `Error::WouldBlock`. +/// +/// # Requirements +/// +/// This macro must be called within a generator body. +/// +/// # Input +/// +/// An expression `$e` that evaluates to `nb::Result` +/// +/// # Output +/// +/// - `Ok(t)` if `$e` evaluates to `Ok(t)` +/// - `Err(e)` if `$e` evaluates to `Err(nb::Error::Other(e))` +#[cfg(feature = "unstable")] +#[macro_export] +macro_rules! await { + ($e:expr) => { + loop { + #[allow(unreachable_patterns)] + match $e { + Err($crate::Error::Other(e)) => + { + #[allow(unreachable_code)] + break Err(e) + } + Err($crate::Error::WouldBlock) => {} // yield (see below) + Ok(x) => break Ok(x), + } + + yield + } + }; +} + +/// Future adapter +/// +/// This is a *try* operation from a `nb::Result` to a `futures::Poll` +/// +/// # Requirements +/// +/// This macro must be called within a function / closure that has signature +/// `fn(..) -> futures::Poll`. +/// +/// This macro requires that the [`futures`] crate is in the root of the crate. +/// +/// [`futures`]: https://crates.io/crates/futures +/// +/// # Input +/// +/// An expression `$e` that evaluates to `nb::Result` +/// +/// # Early return +/// +/// - `Ok(Async::NotReady)` if `$e` evaluates to `Err(nb::Error::WouldBlock)` +/// - `Err(e)` if `$e` evaluates to `Err(nb::Error::Other(e))` +/// +/// # Output +/// +/// `t` if `$e` evaluates to `Ok(t)` +#[cfg(feature = "unstable")] +#[macro_export] +macro_rules! try_nb { + ($e:expr) => { + match $e { + Err($crate::Error::Other(e)) => return Err(e), + Err($crate::Error::WouldBlock) => return Ok(::futures::Async::NotReady), + Ok(x) => x, + } + }; +} diff --git a/src/rust/vendor/nb/.cargo-checksum.json b/src/rust/vendor/nb/.cargo-checksum.json new file mode 100644 index 000000000..91e289570 --- /dev/null +++ b/src/rust/vendor/nb/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"8c8c3a6709b7d9e37d679847e26fff0ec77b2321bb2adb2c93f458a7bf22845f","CODE_OF_CONDUCT.md":"8e25e95078b1a582086587adf8e1d907d43aacee6a072b8630d54a6289e5e0b9","Cargo.toml":"12d0bce4dfc6ac4921ee58cb25e1b03d3d0cb29d261bd175cd5f1e4d407aee43","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"035e70219855119df4273b3c5b97543ae82e0dd60c520416e759107c602f651b","README.md":"0731dbd8d3223e6f7a34aafa90bfc0a822e46958c5f2730420eeaa6782a856b6","src/lib.rs":"9073399b07e2b981f47a7d9523f9d73be83c511f397c372a2f408d8206a8abcd","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"} \ No newline at end of file diff --git a/src/rust/vendor/nb/CHANGELOG.md b/src/rust/vendor/nb/CHANGELOG.md new file mode 100644 index 000000000..8d18a8c3f --- /dev/null +++ b/src/rust/vendor/nb/CHANGELOG.md @@ -0,0 +1,46 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v1.1.0] - 2023-03-07 + +### Added + +- Add `defmt` as optional dependency and implement `defmt::Format` for `Error`, enabled by `defmt-0-3` unstable feature. + +## [v1.0.0] - 2020-07-07 + +### Changed + +- [breaking-change] The `unstable` feature and its code has been removed. + This includes the macros `try_nb!` and `await!`. + +## [v0.1.2] - 2019-04-21 + +### Added + +- `Error` gained a `map` method that lets you transform the error in the + `Error::Other` variant into a different type. + +- `Error` now implements the `From` trait. + +## [v0.1.1] - 2018-01-10 + +### Fixed + +- The `await!` macro now works when the expression `$e` mutably borrows `self`. + +## v0.1.0 - 2018-01-10 + +Initial release + +[Unreleased]: https://github.com/rust-embedded/nb/compare/v1.1.0...HEAD +[v1.1.0]: https://github.com/rust-embedded/nb/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/rust-embedded/nb/compare/v0.1.2...v1.0.0 +[v0.1.2]: https://github.com/rust-embedded/nb/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-embedded/nb/compare/v0.1.0...v0.1.1 diff --git a/src/rust/vendor/nb/CODE_OF_CONDUCT.md b/src/rust/vendor/nb/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..bcefc6a2a --- /dev/null +++ b/src/rust/vendor/nb/CODE_OF_CONDUCT.md @@ -0,0 +1,37 @@ +# The Rust Code of Conduct + +## Conduct + +**Contact**: [HAL team][team] + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [HAL team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[team]: https://github.com/rust-embedded/wg#the-hal-team diff --git a/src/rust/vendor/nb/Cargo.toml b/src/rust/vendor/nb/Cargo.toml new file mode 100644 index 000000000..e1cac94e4 --- /dev/null +++ b/src/rust/vendor/nb/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.60" +name = "nb" +version = "1.1.0" +authors = ["Jorge Aparicio "] +description = "Minimal non-blocking I/O layer" +homepage = "https://github.com/rust-embedded/nb" +documentation = "https://docs.rs/nb" +readme = "README.md" +keywords = [ + "await", + "futures", + "IO", +] +categories = [ + "asynchronous", + "embedded", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-embedded/nb" + +[dependencies.defmt] +version = "0.3" +optional = true + +[features] +defmt-0-3 = ["dep:defmt"] diff --git a/src/rust/vendor/nb/LICENSE-APACHE b/src/rust/vendor/nb/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/nb/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/nb/LICENSE-MIT b/src/rust/vendor/nb/LICENSE-MIT new file mode 100644 index 000000000..a128ba402 --- /dev/null +++ b/src/rust/vendor/nb/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/nb/README.md b/src/rust/vendor/nb/README.md new file mode 100644 index 000000000..0fe23dfdb --- /dev/null +++ b/src/rust/vendor/nb/README.md @@ -0,0 +1,37 @@ +# `nb` + +> Minimal and reusable non-blocking I/O layer + +This project is developed and maintained by the [HAL team][team]. + +## [Documentation](https://docs.rs/nb) + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.35 and up. It *might* +compile with older versions but that may change in any new patch release. + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-hal-team diff --git a/src/rust/vendor/nb/src/lib.rs b/src/rust/vendor/nb/src/lib.rs new file mode 100644 index 000000000..ca5b5918e --- /dev/null +++ b/src/rust/vendor/nb/src/lib.rs @@ -0,0 +1,283 @@ +//! Minimal and reusable non-blocking I/O layer +//! +//! The ultimate goal of this crate is *code reuse*. With this crate you can +//! write *core* I/O APIs that can then be adapted to operate in either blocking +//! or non-blocking manner. Furthermore those APIs are not tied to a particular +//! asynchronous model and can be adapted to work with the `futures` model or +//! with the `async` / `await` model. +//! +//! # Core idea +//! +//! The [`WouldBlock`](enum.Error.html) error variant signals that the operation +//! can't be completed *right now* and would need to block to complete. +//! [`WouldBlock`](enum.Error.html) is a special error in the sense that's not +//! *fatal*; the operation can still be completed by retrying again later. +//! +//! [`nb::Result`](type.Result.html) is based on the API of +//! [`std::io::Result`](https://doc.rust-lang.org/std/io/type.Result.html), +//! which has a `WouldBlock` variant in its +//! [`ErrorKind`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html). +//! +//! We can map [`WouldBlock`](enum.Error.html) to different blocking and +//! non-blocking models: +//! +//! - In blocking mode: [`WouldBlock`](enum.Error.html) means try again right +//! now (i.e. busy wait) +//! - In `futures` mode: [`WouldBlock`](enum.Error.html) means +//! [`Async::NotReady`](https://docs.rs/futures) +//! - In `await` mode: [`WouldBlock`](enum.Error.html) means `yield` +//! (suspend the generator) +//! +//! # How to use this crate +//! +//! Application specific errors can be put inside the `Other` variant in the +//! [`nb::Error`](enum.Error.html) enum. +//! +//! So in your API instead of returning `Result` return +//! `nb::Result` +//! +//! ``` +//! enum MyError { +//! ThisError, +//! ThatError, +//! // .. +//! } +//! +//! // This is a blocking function, so it returns a normal `Result` +//! fn before() -> Result<(), MyError> { +//! // .. +//! # Ok(()) +//! } +//! +//! // This is now a potentially (read: *non*) blocking function so it returns `nb::Result` +//! // instead of blocking +//! fn after() -> nb::Result<(), MyError> { +//! // .. +//! # Ok(()) +//! } +//! ``` +//! +//! You can use `Infallible` to signal that some API has no fatal +//! errors but may block: +//! +//! ``` +//! use core::convert::Infallible; +//! +//! // This returns `Ok(())` or `Err(nb::Error::WouldBlock)` +//! fn maybe_blocking_api() -> nb::Result<(), Infallible> { +//! // .. +//! # Ok(()) +//! } +//! ``` +//! +//! Once your API uses [`nb::Result`] you can leverage the [`block!`], macro +//! to adapt it for blocking operation, or handle scheduling yourself. +//! +//! [`block!`]: macro.block.html +//! [`nb::Result`]: type.Result.html +//! +//! # Examples +//! +//! ## A Core I/O API +//! +//! Imagine the code (crate) below represents a Hardware Abstraction Layer for some microcontroller +//! (or microcontroller family). +//! +//! *In this and the following examples let's assume for simplicity that peripherals are treated +//! as global singletons and that no preemption is possible (i.e. interrupts are disabled).* +//! +//! ``` +//! # use core::convert::Infallible; +//! // This is the `hal` crate +//! use nb; +//! +//! /// An LED +//! pub struct Led; +//! +//! impl Led { +//! pub fn off(&self) { +//! // .. +//! } +//! pub fn on(&self) { +//! // .. +//! } +//! } +//! +//! /// Serial interface +//! pub struct Serial; +//! pub enum Error { +//! Overrun, +//! // .. +//! } +//! +//! impl Serial { +//! /// Reads a single byte from the serial interface +//! pub fn read(&self) -> nb::Result { +//! // .. +//! # Ok(0) +//! } +//! +//! /// Writes a single byte to the serial interface +//! pub fn write(&self, byte: u8) -> nb::Result<(), Error> { +//! // .. +//! # Ok(()) +//! } +//! } +//! +//! /// A timer used for timeouts +//! pub struct Timer; +//! +//! impl Timer { +//! /// Waits until the timer times out +//! pub fn wait(&self) -> nb::Result<(), Infallible> { +//! //^ NOTE the `Infallible` indicates that this operation can block but has no +//! // other form of error +//! +//! // .. +//! # Ok(()) +//! } +//! } +//! ``` +//! +//! ## Blocking mode +//! +//! Turn on an LED for one second and *then* loops back serial data. +//! +//! ``` +//! use core::convert::Infallible; +//! use nb::block; +//! +//! use hal::{Led, Serial, Timer}; +//! +//! # fn main() -> Result<(), Infallible> { +//! // Turn the LED on for one second +//! Led.on(); +//! block!(Timer.wait())?; +//! Led.off(); +//! +//! // Serial interface loopback +//! # return Ok(()); +//! loop { +//! let byte = block!(Serial.read())?; +//! block!(Serial.write(byte))?; +//! } +//! # } +//! +//! # mod hal { +//! # use nb; +//! # use core::convert::Infallible; +//! # pub struct Led; +//! # impl Led { +//! # pub fn off(&self) {} +//! # pub fn on(&self) {} +//! # } +//! # pub struct Serial; +//! # impl Serial { +//! # pub fn read(&self) -> nb::Result { Ok(0) } +//! # pub fn write(&self, _: u8) -> nb::Result<(), Infallible> { Ok(()) } +//! # } +//! # pub struct Timer; +//! # impl Timer { +//! # pub fn wait(&self) -> nb::Result<(), Infallible> { Ok(()) } +//! # } +//! # } +//! ``` +//! +//! # Features +//! +//! - `defmt-0-3` - unstable feature which adds [`defmt::Format`] impl for [`Error`]. + +#![no_std] + +use core::fmt; + +/// A non-blocking result +pub type Result = ::core::result::Result>; + +/// A non-blocking error +/// +/// The main use of this enum is to add a `WouldBlock` variant to an existing +/// error enum. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Error { + /// A different kind of error + Other(E), + /// This operation requires blocking behavior to complete + WouldBlock, +} + +#[cfg(feature = "defmt-0-3")] +impl defmt::Format for Error +where + E: defmt::Format, +{ + fn format(&self, f: defmt::Formatter) { + match *self { + Error::Other(ref e) => defmt::Format::format(e, f), + Error::WouldBlock => defmt::write!(f, "WouldBlock",), + } + } +} + +impl fmt::Debug for Error +where + E: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Other(ref e) => fmt::Debug::fmt(e, f), + Error::WouldBlock => f.write_str("WouldBlock"), + } + } +} + +impl Error { + /// Maps an `Error` to `Error` by applying a function to a contained + /// `Error::Other` value, leaving an `Error::WouldBlock` value untouched. + pub fn map(self, op: F) -> Error + where + F: FnOnce(E) -> T, + { + match self { + Error::Other(e) => Error::Other(op(e)), + Error::WouldBlock => Error::WouldBlock, + } + } +} + +impl From for Error { + fn from(error: E) -> Error { + Error::Other(error) + } +} + +/// Turns the non-blocking expression `$e` into a blocking operation. +/// +/// This is accomplished by continuously calling the expression `$e` until it no +/// longer returns `Error::WouldBlock` +/// +/// # Input +/// +/// An expression `$e` that evaluates to `nb::Result` +/// +/// # Output +/// +/// - `Ok(t)` if `$e` evaluates to `Ok(t)` +/// - `Err(e)` if `$e` evaluates to `Err(nb::Error::Other(e))` +#[macro_export] +macro_rules! block { + ($e:expr) => { + loop { + #[allow(unreachable_patterns)] + match $e { + Err($crate::Error::Other(e)) => + { + #[allow(unreachable_code)] + break Err(e) + } + Err($crate::Error::WouldBlock) => {} + Ok(x) => break Ok(x), + } + } + }; +} diff --git a/src/rust/vendor/nb/triagebot.toml b/src/rust/vendor/nb/triagebot.toml new file mode 100644 index 000000000..fa0824ac5 --- /dev/null +++ b/src/rust/vendor/nb/triagebot.toml @@ -0,0 +1 @@ +[assign] diff --git a/src/rust/vendor/rtt-target/.cargo-checksum.json b/src/rust/vendor/rtt-target/.cargo-checksum.json new file mode 100644 index 000000000..793a22e7d --- /dev/null +++ b/src/rust/vendor/rtt-target/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"818a196728fad94c60bca925a6979ca47bc9cd1d00efa8587bdfb084424051bb","LICENSE":"9a427daacf9c7eedb6f0c4e2b517d8278fe8634cd72a4e38af59c78f7f6a3a2e","README.md":"cba83f91adc5a37c9e0932f863d0b8b6c0729f06da879117e1e7f747a2600123","src/debug.rs":"54b72035d3c6474667432b9c6892c958f74eb455bffeab6ad232d00b0f8811a8","src/init.rs":"1e3d7e0439123f9b457a2a190189fda77ac77d0e16b88bea4269e76e091272db","src/lib.rs":"90dafe887c03ef524a112db090ab955a68f8434fdd0e149a79ebcb1ba961532c","src/print.rs":"84754003f56360117b7e5b45b3f870249464a8c265d06e7f7a825ff735eabac2","src/rtt.rs":"51b288c4df8f04008d9a2d01ecb0e42857fed8d07b7d2abc15794d4c4dac300c"},"package":"10b34c9e6832388e45f3c01f1bb60a016384a0a4ad80cdd7d34913bed25037f0"} \ No newline at end of file diff --git a/src/rust/vendor/rtt-target/Cargo.toml b/src/rust/vendor/rtt-target/Cargo.toml new file mode 100644 index 000000000..ce9122dd4 --- /dev/null +++ b/src/rust/vendor/rtt-target/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "rtt-target" +version = "0.5.0" +authors = ["Matti Virkkunen "] +description = "Target side implementation of the RTT (Real-Time Transfer) I/O protocol" +readme = "README.md" +keywords = [ + "no-std", + "embedded", + "debugging", + "rtt", +] +license = "MIT" +license-file = "LICENSE" +repository = "https://github.com/probe-rs/rtt-target" + +[dependencies.critical-section] +version = "1.0.0" + +[dependencies.ufmt-write] +version = "0.1.0" diff --git a/src/rust/vendor/rtt-target/LICENSE b/src/rust/vendor/rtt-target/LICENSE new file mode 100644 index 000000000..fcba9a1bd --- /dev/null +++ b/src/rust/vendor/rtt-target/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Matti Virkkunen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/rust/vendor/rtt-target/README.md b/src/rust/vendor/rtt-target/README.md new file mode 100644 index 000000000..93bf87296 --- /dev/null +++ b/src/rust/vendor/rtt-target/README.md @@ -0,0 +1,32 @@ +# rtt-target + +[![crates.io](https://img.shields.io/crates/v/rtt-target.svg)](https://crates.io/crates/rtt-target) [![documentation](https://docs.rs/rtt-target/badge.svg)](https://docs.rs/rtt-target) + +Target side implementation of the RTT (Real-Time Transfer) I/O protocol. RTT implements input and output via a debug probe using in-memory ring buffers and polling. This enables debug logging from the microcontroller with minimal delays and no blocking, making it usable even in real-time applications where e.g. semihosting delays cannot be tolerated. + +## [Documentation](https://docs.rs/rtt-target) + +## Platform support + +To use the global `rprintln!` macro, a platform-specific [`critical-section`](https://github.com/rust-embedded/critical-section) implementation is needed for locking. + +Output directly to a channel object with `write!` or the binary `write` method does not require locking and therefore does not need any platform-specific critical section. + +## Usage + +With a platform-specific critical section in use, printing is as simple as: + +```rust +use rtt_target::{rtt_init_print, rprintln}; + +fn main() { + rtt_init_print!(); + loop { + rprintln!("Hello, world!"); + } +} +``` + +## Development + +The examples-cortex-m and panic-test crates come with build files for the venerable STM32F103C8xx by default, but can be easily adapted for any chip as they contain only minimal platform-specific runtime code to get `fn main` to run. diff --git a/src/rust/vendor/rtt-target/src/debug.rs b/src/rust/vendor/rtt-target/src/debug.rs new file mode 100644 index 000000000..8078f8fe2 --- /dev/null +++ b/src/rust/vendor/rtt-target/src/debug.rs @@ -0,0 +1,45 @@ +//! This module contains macros that work exactly like thier equivalents without `debug_*` + +/* From init.rs */ + +/// The same as [`rtt_init`] macro but works only in debug +/// +/// [`rtt_init`](crate::rtt_init) +#[macro_export] +macro_rules! debug_rtt_init { + ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::rtt_init!($($arg)*); }) +} + +/// The same as [`rtt_init_default`] macro but works only in debug +/// +/// [`rtt_init_default`](crate::rtt_init_default) +#[macro_export] +macro_rules! debug_rtt_init_default { + ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::rtt_init_default!($($arg)*); }) +} + +/* From print.rs */ + +/// The same as [`rtt_init_print`] macro but works only in debug +/// +/// [`rtt_init_print`](crate::rtt_init_print) +#[macro_export] +macro_rules! debug_rtt_init_print { + ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::rtt_init_print!($($arg)*); }) +} + +/// The same as [`rprintln`] macro but works only in debug +/// +/// [`rprintln`](crate::rprintln) +#[macro_export] +macro_rules! debug_rprintln { + ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::rprintln!($($arg)*); }) +} + +/// The same as [`rprint`] macro but works only in debug +/// +/// [`rprint`](crate::rprint) +#[macro_export] +macro_rules! debug_rprint { + ($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::rprint!($($arg)*); }) +} diff --git a/src/rust/vendor/rtt-target/src/init.rs b/src/rust/vendor/rtt-target/src/init.rs new file mode 100644 index 000000000..0f632f11a --- /dev/null +++ b/src/rust/vendor/rtt-target/src/init.rs @@ -0,0 +1,207 @@ +/// rtt_init! implementation detail +#[macro_export] +#[doc(hidden)] +macro_rules! rtt_init_repeat { + ({ $($code:tt)+ } { $($acc:tt)* }; $n:literal: { $($_:tt)* } $($tail:tt)*) => { + $crate::rtt_init_repeat!({ $($code)* } { $($code)* $($acc)* }; $($tail)*) + }; + ({ $($code:tt)+ } { $($acc:tt)* };) => { + ($($acc)*) + }; +} + +/// rtt_init! implementation detail +#[macro_export] +#[doc(hidden)] +macro_rules! rtt_init_channels { + ( + $field:expr; + $number:literal: { + size: $size:expr + $(, mode: $mode:path )? + $(, name: $name:literal )? + $(,)? + } + $($tail:tt)* + ) => { + let mut name: *const u8 = core::ptr::null(); + $( name = concat!($name, "\0").as_bytes().as_ptr(); )? + + let mut mode = $crate::ChannelMode::NoBlockSkip; + $( mode = $mode; )? + + $field[$number].init(name, mode, { + static mut _RTT_CHANNEL_BUFFER: MaybeUninit<[u8; $size]> = MaybeUninit::uninit(); + _RTT_CHANNEL_BUFFER.as_mut_ptr() + }); + + $crate::rtt_init_channels!($field; $($tail)*); + }; + ($field:expr;) => { }; +} + +/// rtt_init! implementation detail +#[macro_export] +#[doc(hidden)] +macro_rules! rtt_init_wrappers { + ($field:expr; $cons:path; { $($acc:tt)* }; $n:literal: { $($_:tt)* } $($tail:tt)*) => { + $crate::rtt_init_wrappers!( + $field; + $cons; + { + $($acc)* + $cons(&mut $field[$n] as *mut _), + }; + $($tail)*) + }; + ($field:expr; $cons:path; { $($acc:tt)* };) => { + ($($acc)*) + }; +} + +/// Initializes RTT with the specified channels. Channel numbers, buffer sizes and names can be +/// defined. +/// +/// The syntax looks as follows (note that commas are not allowed anywhere): +/// +/// ``` +/// let channels = rtt_init! { +/// up: { +/// 0: { // channel number +/// size: 1024, // buffer size in bytes +/// mode: NoBlockSkip, // mode (optional, default: NoBlockSkip, see enum ChannelMode) +/// name: "Terminal" // name (optional, default: no name) +/// } +/// 1: { +/// size: 32 +/// } +/// } +/// down: { +/// 0: { +/// size: 16, +/// name: "Terminal" +/// } +/// } +/// }; +/// ``` +/// +/// The channel numbers must start from 0 and not skip any numbers, or otherwise odd things will +/// happen. The order of the channel parameters is fixed, but optional parameters can be left out. +/// This macro should be called once within a function, preferably close to the start of your entry +/// point. The macro must only be called once - if it's called twice in the same program a duplicate +/// symbol error will occur. +/// +/// At compile time the macro will statically reserve space for the RTT control block and the +/// channel buffers. At runtime the macro fills in the structures and prepares them for use. +/// +/// The macro returns a generate struct that contains the channels. The struct for the example above +/// would look as follows: +/// +/// ``` +/// struct Channels { +/// up: (UpChannel, UpChannel), +/// down: (DownChannel,), +/// } +/// ``` +/// +/// The channels can either be accessed by reference or moved out as needed. For example: +/// +/// ``` +/// use core::fmt::Write; +/// +/// let channels = rtt_init! { ... }; +/// let mut output = channels.up.0; +/// writeln!(output, "Hello, world!").ok(); +/// ``` +#[macro_export] +macro_rules! rtt_init { + { + $(up: { $($up:tt)* } )? + $(down: { $($down:tt)* } )? + } => {{ + use core::mem::MaybeUninit; + use core::ptr; + use $crate::UpChannel; + use $crate::DownChannel; + use $crate::rtt::*; + + #[repr(C)] + pub struct RttControlBlock { + header: RttHeader, + up_channels: [RttChannel; $crate::rtt_init_repeat!({ 1 + } { 0 }; $($($up)*)?)], + down_channels: [RttChannel; $crate::rtt_init_repeat!({ 1 + } { 0 }; $($($down)*)?)], + } + + #[used] + #[no_mangle] + #[export_name = "_SEGGER_RTT"] + pub static mut CONTROL_BLOCK: MaybeUninit = MaybeUninit::uninit(); + + unsafe { + ptr::write_bytes(CONTROL_BLOCK.as_mut_ptr(), 0, 1); + + let cb = &mut *CONTROL_BLOCK.as_mut_ptr(); + + $( $crate::rtt_init_channels!(cb.up_channels; $($up)*); )? + $( $crate::rtt_init_channels!(cb.down_channels; $($down)*); )? + + // The header is initialized last to make it less likely an unfinished control block is + // detected by the host. + + cb.header.init(cb.up_channels.len(), cb.down_channels.len()); + + pub struct Channels { + $( pub up: $crate::rtt_init_repeat!({ UpChannel, } {}; $($up)*), )? + $( pub down: $crate::rtt_init_repeat!({ DownChannel, } {}; $($down)*), )? + } + + Channels { + $( up: $crate::rtt_init_wrappers!(cb.up_channels; UpChannel::new; {}; $($up)*), )? + $( down: $crate::rtt_init_wrappers!(cb.down_channels; DownChannel::new; {}; $($down)*), )? + } + } + }}; +} + +/// Initializes RTT with default up/down channels. +/// +/// The default channels are up channel 0 with a 1024 byte buffer and down channel 0 with a 16 byte +/// buffer. Both channels are called "Terminal". This macro is equivalent to: +/// +/// ``` +/// rtt_init! { +/// up: { +/// 0: { +/// size: 1024, +/// name: "Terminal" +/// } +/// } +/// down: { +/// 0: { +/// size: 16, +/// name: "Terminal" +/// } +/// } +/// }; +/// ``` +/// +/// See [`rtt_init`] for more details. +#[macro_export] +macro_rules! rtt_init_default { + () => { + $crate::rtt_init! { + up: { + 0: { + size: 1024, + name: "Terminal" + } + } + down: { + 0: { + size: 16, + name: "Terminal" + } + } + }; + }; +} diff --git a/src/rust/vendor/rtt-target/src/lib.rs b/src/rust/vendor/rtt-target/src/lib.rs new file mode 100644 index 000000000..a395829a3 --- /dev/null +++ b/src/rust/vendor/rtt-target/src/lib.rs @@ -0,0 +1,404 @@ +//! Target side implementation of the RTT (Real-Time Transfer) I/O protocol +//! +//! RTT implements input and output to/from a debug probe using in-memory ring buffers and memory +//! polling. This enables debug logging from the microcontroller with minimal delays and no +//! blocking, making it usable even in real-time applications where e.g. semihosting delays cannot +//! be tolerated. +//! +//! # Hardware support +//! +//! This crate is platform agnostic and can be used on any chip that supports background memory +//! access via its debug interface. The printing macros require a critical section which is +//! platform-dependent. Built-in ARM Cortex-M support can be enabled with the "cortex-m" feature, +//! and RISC-V support can be enabled with the "riscv" feature. +//! +//! To interface with RTT from the host computer, a debug probe such as an ST-Link or J-Link is +//! required. The normal debug protocol (e.g. SWD) is used to access RTT, so no extra connections +//! such as SWO pins are needed. +//! +//! # Initialization +//! +//! RTT must be initialized at the start of your program using one of the init macros. See the +//! macros for more details. +//! +//! The initialization macros return channel objects that can be used for writing and reading. +//! Different channel objects can safely be used concurrently in different contexts without locking. +//! In an interrupt-based application with realtime constraints you could use a separate channel for +//! every interrupt context to allow for lock-free logging. +//! +//! # Channels and virtual terminals +//! +//! RTT supports multiple *channels* in both directions. Up channels go from target to host, and +//! down channels go from host to target. Each channel is identified by its direction and number. +//! +//! By convention channel 0 is reserved for terminal use. In the up direction there is a set of +//! escape sequences that further enable the single channel to be treated as up to 16 *virtual +//! terminals*. This can be used to separate different types of messages (for example, log levels) +//! from each other without having to allocate memory for multiple buffers. As a downside, multiple +//! threads cannot write to the same channel at once, even if using different virtual terminal +//! numbers, so access has to be synchronized. Down channel 0 is conventionally used for keyboard +//! input. +//! +//! **Note:** Some host side programs only display channel 0 by default, so to see the other +//! channels you might need to configure them appropriately. +//! +//! The other channels can be used to either enable concurrent use from multiple sources without +//! locking, or to send e.g. binary data in either direction. +//! +//! Channel 0 can also be used for arbitrary data, but most tools expect it to be plain text. +//! +//! # Channel modes +//! +//! By default, channels start in [`NoBlockSkip`](ChannelMode::NoBlockSkip) mode, which discards +//! data if the buffer is full. This enables RTT to not crash the application if there is no debug +//! probe attached or if the host is not reading the buffers. However if the application outputs +//! faster than the host can read (which is easy to do, because writing is very fast), messages will +//! be lost. Channels can be set to blocking mode if this is desirable, however in that case the +//! application will likely freeze when the buffer fills up if a debugger is not attached. +//! +//! The channel mode can also be changed on the fly by the debug probe. Therefore it may be +//! advantageous to use a non-blocking mode in your microcontroller code, and set a blocking mode as +//! needed when debugging. That way you will never end up with an application that freezes without a +//! debugger connected. +//! +//! # Printing +//! +//! For no-hassle output the [`rprint`] and [`rprintln`] macros are provided. They use a single down +//! channel defined at initialization time, and a critical section for synchronization, and they +//! therefore work exactly like the standard `println` style macros. They can be used from any +//! context. The [`rtt_init_print`] convenience macro initializes printing on channel 0. +//! +//! +//! ``` +//! use rtt_target::{rtt_init_print, rprintln}; +//! +//! fn main() -> ! { +//! rtt_init_print!(); +//! loop { +//! rprintln!("Hello, world!"); +//! } +//! } +//! ``` +//! # Debug +//! +//! To use rtt functionality only in debug builds use macros prefixed with `debug_*`. They have +//! exactly the same functionality as without debug - the only difference is that they are removed +//! when built with `--release`. It's save to use [`debug_rprintln`] and [`debug_rprint`] even if +//! rtt was initialized with [`rtt_init`] instead of [`debug_rtt_init`]. +//! +//! Under the hood this uses the [`debug-assertions`] flag. Set this flag to true to include all debug +//! macros also in release mode. +//! +//! [debug-assertions]: https://doc.rust-lang.org/cargo/reference/profiles.html#debug-assertions +//! +//! ``` +//! use rtt_target::{debug_rtt_init_print, debug_rprintln}; +//! +//! fn main() -> ! { +//! debug_rtt_init_print!(); // nop in --release +//! loop { +//! debug_rprintln!("Hello, world!"); // not present in --release +//! } +//! } +//! ``` +//! +//! The macros also support an extended syntax to print to different RTT virtual terminals. +//! +//! Please note that because a critical section is used, printing into a blocking channel will cause +//! the application to block and freeze when the buffer is full. +//! +//! # Reading +//! +//! The following example shows how to set up the RTT to read simple input sent from the host +//! to the target. +//! +//! ``` +//! use rtt_target::{rtt_init_default, rprintln}; +//! +//! fn main() -> ! { +//! let mode = loop { +//! read = channels.down.0.read(&mut read_buf); +//! for i in 0..read { +//! match read_buf[i] as char { +//! '0' => break 0, +//! '1' => break 1, +//! _ => {} +//! } +//! } +//! }; +//! } +//! ``` + +#![no_std] + +use core::convert::Infallible; +use core::fmt; +use core::mem::MaybeUninit; +use ufmt_write::uWrite; + +#[macro_use] +mod init; + +#[doc(hidden)] +/// Public due to access from macro +pub mod debug; +/// Public due to access from macro +#[doc(hidden)] +pub mod rtt; + +#[macro_use] +mod print; + +pub use print::*; + +/// RTT up (target to host) channel +/// +/// Supports writing binary data directly, or writing strings via [`core::fmt`] macros such as +/// [`write`] as well as the ufmt crate's `uwrite` macros (use the `u` method). +/// +/// Note that the formatted writing implementations diverge slightly from the trait definitions in +/// that if the channel is in non-blocking mode, writing will *not* block. +pub struct UpChannel(*mut rtt::RttChannel); + +unsafe impl Send for UpChannel {} + +impl UpChannel { + /// Public due to access from macro. + #[doc(hidden)] + pub unsafe fn new(channel: *mut rtt::RttChannel) -> Self { + UpChannel(channel) + } + + #[allow(clippy::mut_from_ref)] + fn channel(&self) -> &mut rtt::RttChannel { + unsafe { &mut *self.0 } + } + + /// Writes `buf` to the channel and returns the number of bytes written. Behavior when the + /// buffer is full is subject to the channel blocking mode. + pub fn write(&mut self, buf: &[u8]) -> usize { + let mut writer = self.channel().writer(); + writer.write(buf); + writer.commit() + } + + /// Creates a writer for formatted writing with ufmt. + /// + /// The correct way to use this method is to call it once for each write operation. This is so + /// that non blocking modes will work correctly. + /// + /// ``` + /// let mut output = channels.up.0; + /// uwriteln!(output.u(), "Hello, ufmt!"); + /// ``` + pub fn u(&mut self) -> uWriter { + uWriter(self.channel().writer()) + } + + /// Gets the current blocking mode of the channel. The default is `NoBlockSkip`. + pub fn mode(&self) -> ChannelMode { + self.channel().mode() + } + + /// Sets the blocking mode of the channel + pub fn set_mode(&mut self, mode: ChannelMode) { + self.channel().set_mode(mode) + } + + /// Converts the channel into a virtual terminal that can be used for writing into multiple + /// virtual terminals. + pub fn into_terminal(self) -> TerminalChannel { + TerminalChannel::new(self) + } + + /// Magically creates a channel out of thin air. Return `None` if the channel number is too + /// high, or if the channel has not been initialized. + /// + /// Calling this function will cause a linking error if `rtt_init` has not been called. + /// + /// # Safety + /// + /// It's undefined behavior for something else to access the channel through anything else + /// besides the returned object during or after calling this function. Essentially this function + /// is only safe to use in panic handlers and the like that permanently disable interrupts. + pub unsafe fn conjure(number: usize) -> Option { + extern "C" { + #[link_name = "_SEGGER_RTT"] + static mut CONTROL_BLOCK: MaybeUninit; + } + + if number >= (*CONTROL_BLOCK.as_ptr()).max_up_channels() { + return None; + } + + // First addition moves to the start of the up channel array, second addition moves to the + // correct channel. + let ptr = (CONTROL_BLOCK.as_ptr().add(1) as *mut rtt::RttChannel).add(number); + + if !(*ptr).is_initialized() { + return None; + } + + Some(UpChannel(ptr)) + } +} + +impl fmt::Write for UpChannel { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + self.channel().writer().write_str(s) + } + + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), fmt::Error> { + self.channel().writer().write_fmt(args) + } +} + +/// Writer for ufmt. Don't store an instance of this, but rather create a new one for every write. +#[allow(non_camel_case_types)] +pub struct uWriter<'c>(rtt::RttWriter<'c>); + +impl uWrite for uWriter<'_> { + type Error = Infallible; + + fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { + self.0.write(s.as_bytes()); + Ok(()) + } +} + +/// RTT down (host to target) channel +pub struct DownChannel(*mut rtt::RttChannel); + +unsafe impl Send for DownChannel {} + +impl DownChannel { + /// Public due to access from macro. + #[doc(hidden)] + pub unsafe fn new(channel: *mut rtt::RttChannel) -> Self { + DownChannel(channel) + } + + fn channel(&mut self) -> &mut rtt::RttChannel { + unsafe { &mut *self.0 } + } + + /// Reads up to `buf.len()` bytes from the channel and return the number of bytes read. This + /// method never blocks. + pub fn read(&mut self, buf: &mut [u8]) -> usize { + self.channel().read(buf) + } +} + +/// Specifies what to do when a channel doesn't have enough buffer space for a complete write. +#[derive(Eq, PartialEq)] +#[repr(usize)] +pub enum ChannelMode { + /// Skip writing the data completely if it doesn't fit in its entirety. + NoBlockSkip = 0, + + /// Write as much as possible of the data and ignore the rest. + NoBlockTrim = 1, + + /// Block (spin) if the buffer is full. If within a critical section such as inside + /// [`rprintln`], this will cause the application to freeze until the host reads from the + /// buffer. + BlockIfFull = 2, +} + +/// An up channel that supports writing into multiple virtual terminals within the same buffer. +/// +/// An [`UpChannel`] can be turned into a `TerminalChannel` by using the +/// [`into_terminal`](UpChannel::into_terminal()) method. +/// +/// Virtual terminals allow you to share one buffer for writing multiple streams. The virtual +/// terminals number from 0 to 15 and are implemented with a simple "terminal switch" sequence on +/// the fly, so there is no need to declare them in advance. You could, for example, use different +/// terminal numbers for messages of different priorities to separate them in a viewer program. +/// Printing uses a `TerminalChannel` internally. +pub struct TerminalChannel { + channel: UpChannel, + current: u8, +} + +impl TerminalChannel { + pub(crate) fn new(channel: UpChannel) -> Self { + Self { + channel, + current: 0, + } + } + + /// Creates a writer to write a message to the virtual terminal specified by `number`. + /// + /// The correct way to use this method is to call it once for each write operation. This is so + /// that non blocking modes will work correctly. + /// + /// The writer supports formatted writing with the standard `write` and ufmt's `uwrite`. + pub fn write(&mut self, number: u8) -> TerminalWriter { + const TERMINAL_ID: [u8; 16] = *b"0123456789ABCDEF"; + + let mut writer = self.channel.channel().writer(); + + if number != self.current { + // The terminal switch command must be sent in full so the mode cannot be NoBlockTrim + let mode = self.channel.mode(); + let mode = if mode == ChannelMode::NoBlockTrim { + ChannelMode::NoBlockSkip + } else { + mode + }; + + writer.write_with_mode(mode, &[0xff, TERMINAL_ID[(number & 0x0f) as usize]]); + + self.current = number; + } + + TerminalWriter { + writer, + number, + current: &mut self.current, + } + } + + /// Gets the current blocking mode of the channel. The default is `NoBlockSkip`. + pub fn mode(&self) -> ChannelMode { + self.channel.mode() + } + + /// Sets the blocking mode of the channel + pub fn set_mode(&mut self, mode: ChannelMode) { + self.channel.set_mode(mode) + } +} + +/// Formatted writing operation. Don't store an instance of this, but rather create a new one for +/// every write. +pub struct TerminalWriter<'c> { + writer: rtt::RttWriter<'c>, + number: u8, + current: &'c mut u8, +} + +impl fmt::Write for TerminalWriter<'_> { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + self.writer.write(s.as_bytes()); + Ok(()) + } +} + +impl uWrite for TerminalWriter<'_> { + type Error = Infallible; + + fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { + self.writer.write(s.as_bytes()); + Ok(()) + } +} + +impl Drop for TerminalWriter<'_> { + fn drop(&mut self) { + if !self.writer.is_failed() { + *self.current = self.number; + } + } +} diff --git a/src/rust/vendor/rtt-target/src/print.rs b/src/rust/vendor/rtt-target/src/print.rs new file mode 100644 index 000000000..87e0d1871 --- /dev/null +++ b/src/rust/vendor/rtt-target/src/print.rs @@ -0,0 +1,169 @@ +use core::cell::RefCell; +use core::fmt::{self, Write as _}; +use critical_section::Mutex; + +use crate::{TerminalChannel, TerminalWriter, UpChannel}; + +static PRINT_TERMINAL: Mutex>> = Mutex::new(RefCell::new(None)); + +/// Sets the channel to use for [`rprint`], [`rprintln`], [`debug_rptint`] and [`debug_rprintln`]. +pub fn set_print_channel(channel: UpChannel) { + critical_section::with(|cs| { + *PRINT_TERMINAL.borrow_ref_mut(cs) = Some(TerminalChannel::new(UpChannel(channel.0))) + }); +} + +/// Public due to access from macro. +#[doc(hidden)] +pub mod print_impl { + use super::*; + + fn with_writer(number: u8, f: F) { + critical_section::with(|cs| { + if let Some(term) = &mut *PRINT_TERMINAL.borrow_ref_mut(cs) { + f(term.write(number)) + } + }); + } + + /// Public due to access from macro. + #[doc(hidden)] + pub fn write_str(number: u8, s: &str) { + with_writer(number, |mut w| { + w.write_str(s).ok(); + }); + } + + /// Public due to access from macro. + #[doc(hidden)] + pub fn write_fmt(number: u8, arg: fmt::Arguments) { + with_writer(number, |mut w| { + w.write_fmt(arg).ok(); + }); + } +} + +/// Prints to the print RTT channel. Works just like the standard `print`. +/// +/// Before use the print channel has to be set with [`rtt_init_print`] or [`set_print_channel`]. If +/// the channel isn't set, the message is silently discarded. +/// +/// The macro also supports output to multiple virtual terminals on the channel. Use the syntax +/// ```rprint!(=> 1, "Hello!");``` to write to terminal number 1, for example. Terminal numbers +/// range from 0 to 15. +#[macro_export] +macro_rules! rprint { + (=> $terminal:expr, $s:expr) => { + $crate::print_impl::write_str($terminal, $s); + }; + (=> $terminal:expr, $($arg:tt)*) => { + $crate::print_impl::write_fmt($terminal, format_args!($($arg)*)); + }; + ($s:expr) => { + $crate::print_impl::write_str(0, $s); + }; + ($($arg:tt)*) => { + $crate::print_impl::write_fmt(0, format_args!($($arg)*)); + }; +} + +/// Prints to the print RTT channel, with a newline. Works just like the standard `println`. +/// +/// Before use the print channel has to be set with [`rtt_init_print`] or [`set_print_channel`]. If +/// the channel isn't set, the message is silently discarded. +/// +/// The macro also supports output to multiple virtual terminals on the channel. Use the syntax +/// ```rprintln!(=> 1, "Hello!");``` to write to terminal number 1, for example. Terminal numbers +/// range from 0 to 15. +#[macro_export] +macro_rules! rprintln { + (=> $terminal:expr) => { + $crate::print_impl::write_str($terminal, "\n"); + }; + (=> $terminal:expr, $fmt:expr) => { + $crate::print_impl::write_str($terminal, concat!($fmt, "\n")); + }; + (=> $terminal:expr, $fmt:expr, $($arg:tt)*) => { + $crate::print_impl::write_fmt($terminal, format_args!(concat!($fmt, "\n"), $($arg)*)); + }; + () => { + $crate::print_impl::write_str(0, "\n"); + }; + ($fmt:expr) => { + $crate::print_impl::write_str(0, concat!($fmt, "\n")); + }; + ($fmt:expr, $($arg:tt)*) => { + $crate::print_impl::write_fmt(0, format_args!(concat!($fmt, "\n"), $($arg)*)); + }; +} + +/// Print to RTT and return the value of a given expression for quick debugging. This is equivalent +/// to Rust's `std::dbg!()` macro. +#[macro_export] +macro_rules! rdbg { + (=> $terminal:expr) => { + $crate::rprintln!(=> $terminal, "[{}:{}]", ::core::file!(), ::core::line!()) + }; + (=> $terminal:expr, $val:expr $(,)?) => { + // Use of `match` here is intentional because it affects the lifetimes + // of temporaries - https://stackoverflow.com/a/48732525/1063961 + match $val { + tmp => { + $crate::rprintln!(=> $terminal, "[{}:{}] {} = {:#?}", + ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp); + tmp + } + } + }; + (=> $terminal:expr, $($val:expr),+ $(,)?) => { + ($($crate::rdbg!(=> $terminal, $val)),+,) + }; + () => { + $crate::rprintln!("[{}:{}]", ::core::file!(), ::core::line!()) + }; + ($val:expr $(,)?) => { + // Use of `match` here is intentional because it affects the lifetimes + // of temporaries - https://stackoverflow.com/a/48732525/1063961 + match $val { + tmp => { + $crate::rprintln!("[{}:{}] {} = {:#?}", + ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($($crate::rdbg!($val)),+,) + }; +} + +/// Initializes RTT with a single up channel and sets it as the print channel for the printing +/// macros. +/// +/// The optional arguments specify the blocking mode (default: `NoBlockSkip`) and size of the buffer +/// in bytes (default: 1024). See [`rtt_init`] for more details. +#[macro_export] +macro_rules! rtt_init_print { + ($mode:path, $size:expr) => { + let channels = $crate::rtt_init! { + up: { + 0: { + size: $size, + mode: $mode, + name: "Terminal" + } + } + }; + + $crate::set_print_channel(channels.up.0); + }; + + ($mode:path) => { + $crate::rtt_init_print!($mode, 1024); + }; + + () => { + use $crate::ChannelMode::NoBlockSkip; + $crate::rtt_init_print!(NoBlockSkip, 1024); + }; +} diff --git a/src/rust/vendor/rtt-target/src/rtt.rs b/src/rust/vendor/rtt-target/src/rtt.rs new file mode 100644 index 000000000..765963e4d --- /dev/null +++ b/src/rust/vendor/rtt-target/src/rtt.rs @@ -0,0 +1,282 @@ +//! This module contains the implementation for the RTT protocol. It's not meant to be used directly +//! in user code, and therefore mostly undocumented. The module is only public so that it can be +//! accessed from the rtt_init! macro. + +use crate::ChannelMode; +use core::cmp::min; +use core::fmt; +use core::ptr; +use core::sync::atomic::{fence, AtomicUsize, Ordering::SeqCst}; + +// Note: this is zero-initialized in the initialization macro so all zeros must be a valid value +#[repr(C)] +pub struct RttHeader { + id: [u8; 16], + max_up_channels: usize, + max_down_channels: usize, + // Followed in memory by: + // up_channels: [Channel; max_up_channels] + // down_channels: [Channel; down_up_channels] +} + +impl RttHeader { + /// Initializes the control block header. + /// + /// # Safety + /// + /// The arguments must correspond to the sizes of the arrays that follow the header in memory. + pub unsafe fn init(&mut self, max_up_channels: usize, max_down_channels: usize) { + ptr::write_volatile(&mut self.max_up_channels, max_up_channels); + ptr::write_volatile(&mut self.max_down_channels, max_down_channels); + + // Copy the ID in two parts to avoid having the ID string in memory in full. The ID is + // copied last to make it less likely an unfinished control block is detected by the host. + + ptr::copy_nonoverlapping(b"SEGG_" as *const u8, self.id.as_mut_ptr(), 5); + + fence(SeqCst); + + ptr::copy_nonoverlapping( + b"ER RTT\0\0\0\0\0\0" as *const u8, + self.id.as_mut_ptr().offset(4), + 12, + ); + } + + pub fn max_up_channels(&self) -> usize { + self.max_up_channels + } +} + +// Note: this is zero-initialized in the initialization macro so all zeros must be a valid value +#[repr(C)] +pub struct RttChannel { + name: *const u8, + buffer: *mut u8, + size: usize, + write: AtomicUsize, + read: AtomicUsize, + flags: AtomicUsize, +} + +impl RttChannel { + /// Initializes the channel. + /// + /// # Safety + /// + /// The pointer arguments must point to a valid null-terminated name and writable buffer. + pub unsafe fn init(&mut self, name: *const u8, mode: ChannelMode, buffer: *mut [u8]) { + ptr::write_volatile(&mut self.name, name); + ptr::write_volatile(&mut self.size, (*buffer).len()); + self.set_mode(mode); + + // Set buffer last as it can be used to detect if the channel has been initialized + ptr::write_volatile(&mut self.buffer, buffer as *mut u8); + } + + /// Returns true on a non-null value of the (raw) buffer pointerh + pub fn is_initialized(&self) -> bool { + !self.buffer.is_null() + } + + pub(crate) fn mode(&self) -> ChannelMode { + let mode = self.flags.load(SeqCst) & 3; + + if mode <= 2 { + unsafe { core::mem::transmute(mode) } + } else { + ChannelMode::NoBlockSkip + } + } + + pub(crate) fn set_mode(&self, mode: ChannelMode) { + self.flags + .store((self.flags.load(SeqCst) & !3) | mode as usize, SeqCst); + } + + // This method should only be called for down channels. + pub(crate) fn read(&self, mut buf: &mut [u8]) -> usize { + let (write, mut read) = self.read_pointers(); + + let mut total = 0; + + // Read while buffer contains data and output buffer has space (maximum of two iterations) + while !buf.is_empty() { + let count = min(self.readable_contiguous(write, read), buf.len()); + if count == 0 { + break; + } + + unsafe { + ptr::copy_nonoverlapping(self.buffer.add(read), buf.as_mut_ptr(), count); + } + + total += count; + read += count; + + if read >= self.size { + // Wrap around to start + read = 0; + } + + buf = &mut buf[count..]; + } + + self.read.store(read, SeqCst); + + total + } + + /// This method should only be called for up channels. + pub(crate) fn writer(&self) -> RttWriter<'_> { + RttWriter { + chan: self, + write: self.read_pointers().0, + total: 0, + state: WriteState::Writable, + } + } + + /// Gets the amount of contiguous data available for reading + fn readable_contiguous(&self, write: usize, read: usize) -> usize { + if read > write { + self.size - read + } else { + write - read + } + } + + fn read_pointers(&self) -> (usize, usize) { + let write = self.write.load(SeqCst); + let read = self.read.load(SeqCst); + + if write >= self.size || read >= self.size { + // Pointers have been corrupted. This doesn't happen in well-behaved programs, so + // attempt to reset the buffer. + + self.write.store(0, SeqCst); + self.read.store(0, SeqCst); + return (0, 0); + } + + (write, read) + } +} + +/// A cancellable write operation to an RTT channel. +pub(crate) struct RttWriter<'c> { + chan: &'c RttChannel, + write: usize, + total: usize, + state: WriteState, +} + +#[derive(Eq, PartialEq)] +enum WriteState { + /// Operation can continue + Writable, + + /// Buffer space ran out but the written data will still be committed + Full, + + /// The operation failed and won't be committed, or it has already been committed. + Finished, +} + +impl RttWriter<'_> { + pub fn write(&mut self, buf: &[u8]) { + self.write_with_mode(self.chan.mode(), buf); + } + + pub fn write_with_mode(&mut self, mode: ChannelMode, mut buf: &[u8]) { + while self.state == WriteState::Writable && !buf.is_empty() { + let count = min(self.writable_contiguous(), buf.len()); + + if count == 0 { + // Buffer is full + + match mode { + ChannelMode::NoBlockSkip => { + // Mark the entire operation as failed if even one part cannot be written in + // full. + self.state = WriteState::Finished; + return; + } + + ChannelMode::NoBlockTrim => { + // If the buffer is full, write as much as possible (note: no return), and + // mark the operation as full, which prevents further writes. + self.state = WriteState::Full; + } + + ChannelMode::BlockIfFull => { + // Commit everything written so far and spin until more can be written + self.chan.write.store(self.write, SeqCst); + continue; + } + } + } + + unsafe { + ptr::copy_nonoverlapping(buf.as_ptr(), self.chan.buffer.add(self.write), count); + } + + self.write += count; + self.total += count; + + if self.write >= self.chan.size { + // Wrap around to start + self.write = 0; + } + + buf = &buf[count..]; + } + } + + /// Gets the amount of contiguous space available for writing + fn writable_contiguous(&self) -> usize { + let read = self.chan.read_pointers().1; + + if read > self.write { + read - self.write - 1 + } else if read == 0 { + self.chan.size - self.write - 1 + } else { + self.chan.size - self.write + } + } + + pub fn is_failed(&self) -> bool { + self.state != WriteState::Finished + } + + pub fn commit(mut self) -> usize { + self.commit_impl(); + + self.total + } + + fn commit_impl(&mut self) { + match self.state { + WriteState::Finished => (), + WriteState::Full | WriteState::Writable => { + // Commit the write pointer so the host can see the new data + self.chan.write.store(self.write, SeqCst); + self.state = WriteState::Finished; + } + } + } +} + +impl Drop for RttWriter<'_> { + fn drop(&mut self) { + self.commit_impl(); + } +} + +impl fmt::Write for RttWriter<'_> { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + self.write(s.as_bytes()); + Ok(()) + } +} diff --git a/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json b/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json index ce1535e33..1facd4319 100644 --- a/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json +++ b/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"32df7c9030f058cde971d4fa46f775fe8498948995ef31197712dfb44bbc5a2e","src/lib.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},"package":"ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86"} \ No newline at end of file +{"files":{"Cargo.toml":"fcf31f07045ef33a614ef32be6a21f5e19c4c9308ab0eb6547aa533e268dbd44","src/lib.rs":"d3133155f040a09a74660f4fcf9b64e51a252e385b3483286fc5eed1b3cca4ec"},"package":"f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3"} \ No newline at end of file diff --git a/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml b/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml index 4075e82bf..98f52591f 100644 --- a/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml +++ b/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml @@ -3,19 +3,29 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" name = "rustc-std-workspace-alloc" -version = "1.0.0" +version = "1.0.1" authors = ["Alex Crichton "] -description = "workspace hack" +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = """ +crate for integration of crates.io crates into rust-lang/rust standard library workspace +""" +readme = false license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/rust/tree/master/src/rustc-std-workspace" -[dependencies] +[lib] +name = "rustc_std_workspace_alloc" +path = "src/lib.rs" diff --git a/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs b/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs index e69de29bb..938b8bb29 100644 --- a/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs +++ b/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs @@ -0,0 +1,3 @@ +#![no_std] +extern crate alloc as the_alloc; +pub use the_alloc::*; diff --git a/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json b/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json index 6ec3d59c0..7bda8d07e 100644 --- a/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json +++ b/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ac7ce15b820ee532ba739d5fc54f1b22f3052ed794ce72534655fd4a3688655f","src/lib.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},"package":"1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"} \ No newline at end of file +{"files":{"Cargo.toml":"c41de1976263e57febc55cdb8b59c2b2671530e708a07aee0c8234b034fb1f94","src/lib.rs":"ed0e785d71613f3e0aa475f90ee873eab8063e388ef9fde9bad92b1270ecc0c4"},"package":"aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955"} \ No newline at end of file diff --git a/src/rust/vendor/rustc-std-workspace-core/Cargo.toml b/src/rust/vendor/rustc-std-workspace-core/Cargo.toml index 7a5a96154..b01ae5fb4 100644 --- a/src/rust/vendor/rustc-std-workspace-core/Cargo.toml +++ b/src/rust/vendor/rustc-std-workspace-core/Cargo.toml @@ -3,18 +3,29 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] +edition = "2021" name = "rustc-std-workspace-core" -version = "1.0.0" +version = "1.0.1" authors = ["Alex Crichton "] -description = "Explicitly empty crate for rust-lang/rust integration\n" +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = """ +crate for integration of crates.io crates into rust-lang/rust standard library workspace +""" +readme = false license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/rust/tree/master/src/rustc-std-workspace" -[dependencies] +[lib] +name = "rustc_std_workspace_core" +path = "src/lib.rs" diff --git a/src/rust/vendor/rustc-std-workspace-core/src/lib.rs b/src/rust/vendor/rustc-std-workspace-core/src/lib.rs index e69de29bb..38b1615a0 100644 --- a/src/rust/vendor/rustc-std-workspace-core/src/lib.rs +++ b/src/rust/vendor/rustc-std-workspace-core/src/lib.rs @@ -0,0 +1,3 @@ +#![no_std] +extern crate core as the_core; +pub use the_core::*; diff --git a/src/rust/vendor/rustc_version-0.2.3/.cargo-checksum.json b/src/rust/vendor/rustc_version-0.2.3/.cargo-checksum.json new file mode 100644 index 000000000..f86fe1cf8 --- /dev/null +++ b/src/rust/vendor/rustc_version-0.2.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"80b9fb136c8c2945b4875b05b0f5a4b11e4722997e751f17d8d3f241d7c684db","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"58bd14a1dfa1d828e6e99f35c3b7c2149d08e2d990d6ca93f92ab8ffb43275b7","src/errors.rs":"b28c2eeb1278fc3e8d68a64b177034faed67f6762335729d3a6d1e61be8fb034","src/lib.rs":"92a32673f77961724bc52b872781f06d22d166f06838c9582c5adae3c5214f51"},"package":"138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"} \ No newline at end of file diff --git a/src/rust/vendor/rustc_version-0.2.3/Cargo.toml b/src/rust/vendor/rustc_version-0.2.3/Cargo.toml new file mode 100644 index 000000000..3b252b85a --- /dev/null +++ b/src/rust/vendor/rustc_version-0.2.3/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rustc_version" +version = "0.2.3" +authors = ["Marvin Löbel "] +description = "A library for querying the version of a installed rustc compiler" +documentation = "https://docs.rs/rustc_version/" +readme = "README.md" +keywords = ["version", "rustc"] +license = "MIT/Apache-2.0" +repository = "https://github.com/Kimundi/rustc-version-rs" +[dependencies.semver] +version = "0.9" +[badges.travis-ci] +repository = "Kimundi/rustc-version-rs" diff --git a/src/rust/vendor/rustc_version-0.2.3/LICENSE-APACHE b/src/rust/vendor/rustc_version-0.2.3/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/rustc_version-0.2.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/rustc_version-0.2.3/LICENSE-MIT b/src/rust/vendor/rustc_version-0.2.3/LICENSE-MIT new file mode 100644 index 000000000..40b8817a4 --- /dev/null +++ b/src/rust/vendor/rustc_version-0.2.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/rustc_version-0.2.3/README.md b/src/rust/vendor/rustc_version-0.2.3/README.md new file mode 100644 index 000000000..f491ca964 --- /dev/null +++ b/src/rust/vendor/rustc_version-0.2.3/README.md @@ -0,0 +1,75 @@ +rustc-version-rs +============== + +A library for querying the version of a `rustc` compiler. + +This can be used by build scripts or other tools dealing with Rust sources +to make decisions based on the version of the compiler. + +[![Travis-CI Status](https://travis-ci.org/Kimundi/rustc-version-rs.png?branch=master)](https://travis-ci.org/Kimundi/rustc-version-rs) + +# Getting Started + +[rustc-version-rs is available on crates.io](https://crates.io/crates/rustc_version). +It is recommended to look there for the newest released version, as well as links to the newest builds of the docs. + +At the point of the last update of this README, the latest published version could be used like this: + +Add the following dependency to your Cargo manifest... + +```toml +[build-dependencies] +rustc_version = "0.2" +``` + +...and see the [docs](http://kimundi.github.io/rustc-version-rs/rustc_version/index.html) for how to use it. + +# Example + +```rust +// This could be a cargo build script + +extern crate rustc_version; +use rustc_version::{version, version_meta, Channel, Version}; + +fn main() { + // Assert we haven't travelled back in time + assert!(version().unwrap().major >= 1); + + // Set cfg flags depending on release channel + match version_meta().unwrap().channel { + Channel::Stable => { + println!("cargo:rustc-cfg=RUSTC_IS_STABLE"); + } + Channel::Beta => { + println!("cargo:rustc-cfg=RUSTC_IS_BETA"); + } + Channel::Nightly => { + println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY"); + } + Channel::Dev => { + println!("cargo:rustc-cfg=RUSTC_IS_DEV"); + } + } + + // Check for a minimum version + if version().unwrap() >= Version::parse("1.4.0").unwrap() { + println!("cargo:rustc-cfg=compiler_has_important_bugfix"); + } +} +``` + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/src/rust/vendor/rustc_version-0.2.3/src/errors.rs b/src/rust/vendor/rustc_version-0.2.3/src/errors.rs new file mode 100644 index 000000000..54557b6e2 --- /dev/null +++ b/src/rust/vendor/rustc_version-0.2.3/src/errors.rs @@ -0,0 +1,79 @@ +use std::{self, error, fmt, io, str}; +use semver::{self, Identifier}; + +/// The error type for this crate. +#[derive(Debug)] +pub enum Error { + /// An error ocurrend when executing the `rustc` command. + CouldNotExecuteCommand(io::Error), + /// The output of `rustc -vV` was not valid utf-8. + Utf8Error(str::Utf8Error), + /// The output of `rustc -vV` was not in the expected format. + UnexpectedVersionFormat, + /// An error ocurred in parsing a `VersionReq`. + ReqParseError(semver::ReqParseError), + /// An error ocurred in parsing the semver. + SemVerError(semver::SemVerError), + /// The pre-release tag is unknown. + UnknownPreReleaseTag(Identifier), +} +use Error::*; + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::error::Error; + match *self { + CouldNotExecuteCommand(ref e) => write!(f, "{}: {}", self.description(), e), + Utf8Error(_) => write!(f, "{}", self.description()), + UnexpectedVersionFormat => write!(f, "{}", self.description()), + ReqParseError(ref e) => write!(f, "{}: {}", self.description(), e), + SemVerError(ref e) => write!(f, "{}: {}", self.description(), e), + UnknownPreReleaseTag(ref i) => write!(f, "{}: {}", self.description(), i), + } + } +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + match *self { + CouldNotExecuteCommand(ref e) => Some(e), + Utf8Error(ref e) => Some(e), + UnexpectedVersionFormat => None, + ReqParseError(ref e) => Some(e), + SemVerError(ref e) => Some(e), + UnknownPreReleaseTag(_) => None, + } + } + + fn description(&self) -> &str { + match *self { + CouldNotExecuteCommand(_) => "could not execute command", + Utf8Error(_) => "invalid UTF-8 output from `rustc -vV`", + UnexpectedVersionFormat => "unexpected `rustc -vV` format", + ReqParseError(_) => "error parsing version requirement", + SemVerError(_) => "error parsing version", + UnknownPreReleaseTag(_) => "unknown pre-release tag", + } + } +} + +macro_rules! impl_from { + ($($err_ty:ty => $variant:ident),* $(,)*) => { + $( + impl From<$err_ty> for Error { + fn from(e: $err_ty) -> Error { + Error::$variant(e) + } + } + )* + } +} + +impl_from! { + str::Utf8Error => Utf8Error, + semver::SemVerError => SemVerError, + semver::ReqParseError => ReqParseError, +} + +/// The result type for this crate. +pub type Result = std::result::Result; diff --git a/src/rust/vendor/rustc_version-0.2.3/src/lib.rs b/src/rust/vendor/rustc_version-0.2.3/src/lib.rs new file mode 100644 index 000000000..c03828898 --- /dev/null +++ b/src/rust/vendor/rustc_version-0.2.3/src/lib.rs @@ -0,0 +1,347 @@ +// Copyright 2016 rustc-version-rs developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![warn(missing_docs)] + +//! Simple library for getting the version information of a `rustc` +//! compiler. +//! +//! This can be used by build scripts or other tools dealing with Rust sources +//! to make decisions based on the version of the compiler. +//! +//! It calls `$RUSTC --version -v` and parses the output, falling +//! back to `rustc` if `$RUSTC` is not set. +//! +//! # Example +//! +//! ```rust +//! // This could be a cargo build script +//! +//! extern crate rustc_version; +//! use rustc_version::{version, version_meta, Channel, Version}; +//! +//! fn main() { +//! // Assert we haven't travelled back in time +//! assert!(version().unwrap().major >= 1); +//! +//! // Set cfg flags depending on release channel +//! match version_meta().unwrap().channel { +//! Channel::Stable => { +//! println!("cargo:rustc-cfg=RUSTC_IS_STABLE"); +//! } +//! Channel::Beta => { +//! println!("cargo:rustc-cfg=RUSTC_IS_BETA"); +//! } +//! Channel::Nightly => { +//! println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY"); +//! } +//! Channel::Dev => { +//! println!("cargo:rustc-cfg=RUSTC_IS_DEV"); +//! } +//! } +//! +//! // Check for a minimum version +//! if version().unwrap() >= Version::parse("1.4.0").unwrap() { +//! println!("cargo:rustc-cfg=compiler_has_important_bugfix"); +//! } +//! } +//! ``` + +extern crate semver; +use semver::Identifier; +use std::process::Command; +use std::{env, str}; +use std::ffi::OsString; + +// Convenience re-export to allow version comparison without needing to add +// semver crate. +pub use semver::Version; + +mod errors; +pub use errors::{Error, Result}; + +/// Release channel of the compiler. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub enum Channel { + /// Development release channel + Dev, + /// Nightly release channel + Nightly, + /// Beta release channel + Beta, + /// Stable release channel + Stable, +} + +/// Rustc version plus metada like git short hash and build date. +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct VersionMeta { + /// Version of the compiler + pub semver: Version, + + /// Git short hash of the build of the compiler + pub commit_hash: Option, + + /// Commit date of the compiler + pub commit_date: Option, + + /// Build date of the compiler; this was removed between Rust 1.0.0 and 1.1.0. + pub build_date: Option, + + /// Release channel of the compiler + pub channel: Channel, + + /// Host target triple of the compiler + pub host: String, + + /// Short version string of the compiler + pub short_version_string: String, +} + +impl VersionMeta { + /// Returns the version metadata for `cmd`, which should be a `rustc` command. + pub fn for_command(cmd: Command) -> Result { + let mut cmd = cmd; + + let out = cmd.arg("-vV").output().map_err(Error::CouldNotExecuteCommand)?; + let out = str::from_utf8(&out.stdout)?; + + version_meta_for(out) + } +} + +/// Returns the `rustc` SemVer version. +pub fn version() -> Result { + Ok(version_meta()?.semver) +} + +/// Returns the `rustc` SemVer version and additional metadata +/// like the git short hash and build date. +pub fn version_meta() -> Result { + let cmd = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); + + VersionMeta::for_command(Command::new(cmd)) +} + +/// Parses a "rustc -vV" output string and returns +/// the SemVer version and additional metadata +/// like the git short hash and build date. +pub fn version_meta_for(verbose_version_string: &str) -> Result { + let out: Vec<_> = verbose_version_string.lines().collect(); + + if !(out.len() >= 6 && out.len() <= 8) { + return Err(Error::UnexpectedVersionFormat); + } + + let short_version_string = out[0]; + + fn expect_prefix<'a>(line: &'a str, prefix: &str) -> Result<&'a str> { + if line.starts_with(prefix) { + Ok(&line[prefix.len()..]) + } else { + Err(Error::UnexpectedVersionFormat) + } + } + + let commit_hash = match expect_prefix(out[2], "commit-hash: ")? { + "unknown" => None, + hash => Some(hash.to_owned()), + }; + + let commit_date = match expect_prefix(out[3], "commit-date: ")? { + "unknown" => None, + hash => Some(hash.to_owned()), + }; + + // Handle that the build date may or may not be present. + let mut idx = 4; + let mut build_date = None; + if out[idx].starts_with("build-date") { + build_date = match expect_prefix(out[idx], "build-date: ")? { + "unknown" => None, + s => Some(s.to_owned()), + }; + idx += 1; + } + + let host = expect_prefix(out[idx], "host: ")?; + idx += 1; + let release = expect_prefix(out[idx], "release: ")?; + + let semver: Version = release.parse()?; + + let channel = if semver.pre.is_empty() { + Channel::Stable + } else { + match semver.pre[0] { + Identifier::AlphaNumeric(ref s) if s == "dev" => Channel::Dev, + Identifier::AlphaNumeric(ref s) if s == "beta" => Channel::Beta, + Identifier::AlphaNumeric(ref s) if s == "nightly" => Channel::Nightly, + ref x => return Err(Error::UnknownPreReleaseTag(x.clone())), + } + }; + + Ok(VersionMeta { + semver: semver, + commit_hash: commit_hash, + commit_date: commit_date, + build_date: build_date, + channel: channel, + host: host.into(), + short_version_string: short_version_string.into(), + }) +} + +#[test] +fn smoketest() { + let v = version().unwrap(); + assert!(v.major >= 1); + + let v = version_meta().unwrap(); + assert!(v.semver.major >= 1); + + assert!(version().unwrap() >= Version::parse("1.0.0").unwrap()); +} + +#[test] +fn parse_unexpected() { + let res = version_meta_for( +"rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14) +binary: rustc +commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e +commit-date: 2015-05-13 +rust-birthday: 2015-05-14 +host: x86_64-unknown-linux-gnu +release: 1.0.0"); + + assert!(match res { + Err(Error::UnexpectedVersionFormat) => true, + _ => false, + }); + +} + +#[test] +fn parse_1_0_0() { + let version = version_meta_for( +"rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14) +binary: rustc +commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e +commit-date: 2015-05-13 +build-date: 2015-05-14 +host: x86_64-unknown-linux-gnu +release: 1.0.0").unwrap(); + + assert_eq!(version.semver, Version::parse("1.0.0").unwrap()); + assert_eq!(version.commit_hash, Some("a59de37e99060162a2674e3ff45409ac73595c0e".into())); + assert_eq!(version.commit_date, Some("2015-05-13".into())); + assert_eq!(version.build_date, Some("2015-05-14".into())); + assert_eq!(version.channel, Channel::Stable); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)"); +} + + +#[test] +fn parse_unknown() { + let version = version_meta_for( +"rustc 1.3.0 +binary: rustc +commit-hash: unknown +commit-date: unknown +host: x86_64-unknown-linux-gnu +release: 1.3.0").unwrap(); + + assert_eq!(version.semver, Version::parse("1.3.0").unwrap()); + assert_eq!(version.commit_hash, None); + assert_eq!(version.commit_date, None); + assert_eq!(version.channel, Channel::Stable); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.3.0"); +} + +#[test] +fn parse_nightly() { + let version = version_meta_for( +"rustc 1.5.0-nightly (65d5c0833 2015-09-29) +binary: rustc +commit-hash: 65d5c083377645a115c4ac23a620d3581b9562b6 +commit-date: 2015-09-29 +host: x86_64-unknown-linux-gnu +release: 1.5.0-nightly").unwrap(); + + assert_eq!(version.semver, Version::parse("1.5.0-nightly").unwrap()); + assert_eq!(version.commit_hash, Some("65d5c083377645a115c4ac23a620d3581b9562b6".into())); + assert_eq!(version.commit_date, Some("2015-09-29".into())); + assert_eq!(version.channel, Channel::Nightly); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.5.0-nightly (65d5c0833 2015-09-29)"); +} + +#[test] +fn parse_stable() { + let version = version_meta_for( +"rustc 1.3.0 (9a92aaf19 2015-09-15) +binary: rustc +commit-hash: 9a92aaf19a64603b02b4130fe52958cc12488900 +commit-date: 2015-09-15 +host: x86_64-unknown-linux-gnu +release: 1.3.0").unwrap(); + + assert_eq!(version.semver, Version::parse("1.3.0").unwrap()); + assert_eq!(version.commit_hash, Some("9a92aaf19a64603b02b4130fe52958cc12488900".into())); + assert_eq!(version.commit_date, Some("2015-09-15".into())); + assert_eq!(version.channel, Channel::Stable); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.3.0 (9a92aaf19 2015-09-15)"); +} + +#[test] +fn parse_1_16_0_nightly() { + let version = version_meta_for( +"rustc 1.16.0-nightly (5d994d8b7 2017-01-05) +binary: rustc +commit-hash: 5d994d8b7e482e87467d4a521911477bd8284ce3 +commit-date: 2017-01-05 +host: x86_64-unknown-linux-gnu +release: 1.16.0-nightly +LLVM version: 3.9").unwrap(); + + assert_eq!(version.semver, Version::parse("1.16.0-nightly").unwrap()); + assert_eq!(version.commit_hash, Some("5d994d8b7e482e87467d4a521911477bd8284ce3".into())); + assert_eq!(version.commit_date, Some("2017-01-05".into())); + assert_eq!(version.channel, Channel::Nightly); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.16.0-nightly (5d994d8b7 2017-01-05)"); +} + +/* +#[test] +fn version_matches_replacement() { + let f = |s1: &str, s2: &str| { + let a = Version::parse(s1).unwrap(); + let b = Version::parse(s2).unwrap(); + println!("{} <= {} : {}", s1, s2, a <= b); + }; + + println!(); + + f("1.5.0", "1.5.0"); + f("1.5.0-nightly", "1.5.0"); + f("1.5.0", "1.5.0-nightly"); + f("1.5.0-nightly", "1.5.0-nightly"); + + f("1.5.0", "1.6.0"); + f("1.5.0-nightly", "1.6.0"); + f("1.5.0", "1.6.0-nightly"); + f("1.5.0-nightly", "1.6.0-nightly"); + + panic!(); + +} +*/ diff --git a/src/rust/vendor/semver-0.9.0/.cargo-checksum.json b/src/rust/vendor/semver-0.9.0/.cargo-checksum.json new file mode 100644 index 000000000..2f9af6eca --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"a5b995796b5559de8975a6fee7166c9fda6c21b449ec90bef5f9baaeddd479a5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"c780d8c3c802c5fe2c316127900385010c3e57f71c851eea9e8ed8495e2030dd","src/lib.rs":"cb1725a8bb90c1043f187c6ba504d0a9d07793e2f39f5205f926c58849311770","src/version.rs":"ffdf9c628597b889f149f3b2b1245b97c774eae1ce7030bd19235eabecaaede0","src/version_req.rs":"40d20720f5fdc0b3d9e398e64eb448a65987229bd322cab0fedf0cf1843f3bd8","tests/deprecation.rs":"b5ec79e19d61968d05b96b876c449e54d43cbd1762c6e63c23c3470f9db56292","tests/regression.rs":"180b699ad029b81e6135d42f0a8e6d782177bc29a41132f875ee6f8607a46b56","tests/serde.rs":"cdbbefc576ffcc814c30dad9598ab87a7fd9d14c5f42f1349e1db6afc72f8fed"},"package":"1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"} \ No newline at end of file diff --git a/src/rust/vendor/semver-0.9.0/Cargo.toml b/src/rust/vendor/semver-0.9.0/Cargo.toml new file mode 100644 index 000000000..7749f76c3 --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "semver" +version = "0.9.0" +authors = ["Steve Klabnik ", "The Rust Project Developers"] +description = "Semantic version parsing and comparison.\n" +homepage = "https://docs.rs/crate/semver/" +documentation = "https://docs.rs/crate/semver/" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/steveklabnik/semver" +[dependencies.semver-parser] +version = "0.7.0" + +[dependencies.serde] +version = "1.0" +optional = true +[dev-dependencies.crates-index] +version = "0.5.0" + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.tempdir] +version = "0.3.4" + +[features] +default = [] +ci = ["serde"] +[badges.travis-ci] +repository = "steveklabnik/semver" diff --git a/src/rust/vendor/semver-0.9.0/LICENSE-APACHE b/src/rust/vendor/semver-0.9.0/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/semver-0.9.0/LICENSE-MIT b/src/rust/vendor/semver-0.9.0/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/semver-0.9.0/README.md b/src/rust/vendor/semver-0.9.0/README.md new file mode 100644 index 000000000..2a5306d4c --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/README.md @@ -0,0 +1,103 @@ +semver +====== + +Semantic version parsing and comparison. + +[![Build Status](https://api.travis-ci.org/steveklabnik/semver.svg?branch=master)](https://travis-ci.org/steveklabnik/semver) + +[Documentation](https://steveklabnik.github.io/semver) + +Semantic versioning (see http://semver.org/) is a set of rules for +assigning version numbers. + +## SemVer and the Rust ecosystem + +Rust itself follows the SemVer specification, as does its standard libraries. The two are +not tied together. + +[Cargo](https://crates.io), Rust's package manager, uses SemVer to determine which versions of +packages you need installed. + +## Installation + +To use `semver`, add this to your `[dependencies]` section: + +```toml +semver = "0.7.0" +``` + +And this to your crate root: + +```rust +extern crate semver; +``` + +## Versions + +At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse` +method: + +```rust +use semver::Version; + +assert!(Version::parse("1.2.3") == Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec!(), + build: vec!(), +})); +``` + +If you have multiple `Version`s, you can use the usual comparison operators to compare them: + +```rust +use semver::Version; + +assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); +assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); +``` + +## Requirements + +The `semver` crate also provides the ability to compare requirements, which are more complex +comparisons. + +For example, creating a requirement that only matches versions greater than or +equal to 1.0.0: + +```rust +use semver::Version; +use semver::VersionReq; + +let r = VersionReq::parse(">= 1.0.0").unwrap(); +let v = Version::parse("1.0.0").unwrap(); + +assert!(r.to_string() == ">= 1.0.0".to_string()); +assert!(r.matches(&v)) +``` + +It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at +https://www.npmjs.org/doc/misc/semver.html + +**Tilde requirements** specify a minimal version with some updates: + +```notrust +~1.2.3 := >=1.2.3 <1.3.0 +~1.2 := >=1.2.0 <1.3.0 +~1 := >=1.0.0 <2.0.0 +``` + +**Caret requirements** allow SemVer compatible updates to a specified version, +`0.x` and `0.x+1` are not considered compatible, but `1.x` and `1.x+1` are. + +`0.0.x` is not considered compatible with any other version. +Missing minor and patch versions are desugared to `0` but allow flexibility for that value. + +```notrust +^1.2.3 := >=1.2.3 <2.0.0 +^0.2.3 := >=0.2.3 <0.3.0 +^0.0.3 := >=0.0.3 <0.0.4 +^0.0 := >=0.0.0 <0.1.0 +^0 := >=0.0.0 <1.0.0 +``` diff --git a/src/rust/vendor/semver-0.9.0/src/lib.rs b/src/rust/vendor/semver-0.9.0/src/lib.rs new file mode 100644 index 000000000..a38aae0e1 --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/src/lib.rs @@ -0,0 +1,182 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Semantic version parsing and comparison. +//! +//! Semantic versioning (see http://semver.org/) is a set of rules for +//! assigning version numbers. +//! +//! ## SemVer overview +//! +//! Given a version number MAJOR.MINOR.PATCH, increment the: +//! +//! 1. MAJOR version when you make incompatible API changes, +//! 2. MINOR version when you add functionality in a backwards-compatible +//! manner, and +//! 3. PATCH version when you make backwards-compatible bug fixes. +//! +//! Additional labels for pre-release and build metadata are available as +//! extensions to the MAJOR.MINOR.PATCH format. +//! +//! Any references to 'the spec' in this documentation refer to [version 2.0 of +//! the SemVer spec](http://semver.org/spec/v2.0.0.html). +//! +//! ## SemVer and the Rust ecosystem +//! +//! Rust itself follows the SemVer specification, as does its standard +//! libraries. The two are not tied together. +//! +//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine +//! which versions of packages you need installed. +//! +//! ## Versions +//! +//! At its simplest, the `semver` crate allows you to construct `Version` +//! objects using the `parse` method: +//! +//! ```{rust} +//! use semver::Version; +//! +//! assert!(Version::parse("1.2.3") == Ok(Version { +//! major: 1, +//! minor: 2, +//! patch: 3, +//! pre: vec!(), +//! build: vec!(), +//! })); +//! ``` +//! +//! If you have multiple `Version`s, you can use the usual comparison operators +//! to compare them: +//! +//! ```{rust} +//! use semver::Version; +//! +//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); +//! assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); +//! ``` +//! +//! If you explicitly need to modify a Version, SemVer also allows you to +//! increment the major, minor, and patch numbers in accordance with the spec. +//! +//! Please note that in order to do this, you must use a mutable Version: +//! +//! ```{rust} +//! use semver::Version; +//! +//! let mut bugfix_release = Version::parse("1.0.0").unwrap(); +//! bugfix_release.increment_patch(); +//! +//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1")); +//! ``` +//! +//! When incrementing the minor version number, the patch number resets to zero +//! (in accordance with section 7 of the spec) +//! +//! ```{rust} +//! use semver::Version; +//! +//! let mut feature_release = Version::parse("1.4.6").unwrap(); +//! feature_release.increment_minor(); +//! +//! assert_eq!(Ok(feature_release), Version::parse("1.5.0")); +//! ``` +//! +//! Similarly, when incrementing the major version number, the patch and minor +//! numbers reset to zero (in accordance with section 8 of the spec) +//! +//! ```{rust} +//! use semver::Version; +//! +//! let mut chrome_release = Version::parse("41.5.5377").unwrap(); +//! chrome_release.increment_major(); +//! +//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0")); +//! ``` +//! +//! ## Requirements +//! +//! The `semver` crate also provides the ability to compare requirements, which +//! are more complex comparisons. +//! +//! For example, creating a requirement that only matches versions greater than +//! or equal to 1.0.0: +//! +//! ```{rust} +//! # #![allow(unstable)] +//! use semver::Version; +//! use semver::VersionReq; +//! +//! let r = VersionReq::parse(">= 1.0.0").unwrap(); +//! let v = Version::parse("1.0.0").unwrap(); +//! +//! assert!(r.to_string() == ">= 1.0.0".to_string()); +//! assert!(r.matches(&v)) +//! ``` +//! +//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at +//! https://www.npmjs.org/doc/misc/semver.html +//! +//! **Tilde requirements** specify a minimal version with some updates: +//! +//! ```notrust +//! ~1.2.3 := >=1.2.3 <1.3.0 +//! ~1.2 := >=1.2.0 <1.3.0 +//! ~1 := >=1.0.0 <2.0.0 +//! ``` +//! +//! **Caret requirements** allow SemVer compatible updates to a specified +//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and +//! `1.x+1` are. +//! +//! `0.0.x` is not considered compatible with any other version. +//! Missing minor and patch versions are desugared to `0` but allow flexibility +//! for that value. +//! +//! ```notrust +//! ^1.2.3 := >=1.2.3 <2.0.0 +//! ^0.2.3 := >=0.2.3 <0.3.0 +//! ^0.0.3 := >=0.0.3 <0.0.4 +//! ^0.0 := >=0.0.0 <0.1.0 +//! ^0 := >=0.0.0 <1.0.0 +//! ``` +//! +//! **Wildcard requirements** allows parsing of version requirements of the +//! formats `*`, `x.*` and `x.y.*`. +//! +//! ```notrust +//! * := >=0.0.0 +//! 1.* := >=1.0.0 <2.0.0 +//! 1.2.* := >=1.2.0 <1.3.0 +//! ``` + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +extern crate semver_parser; + +// Serialization and deserialization support for version numbers +#[cfg(feature = "serde")] +extern crate serde; + +// We take the common approach of keeping our own module system private, and +// just re-exporting the interface that we want. + +pub use version::{Version, Identifier, SemVerError}; +pub use version::Identifier::{Numeric, AlphaNumeric}; +pub use version_req::{VersionReq, ReqParseError}; + +// SemVer-compliant versions. +mod version; + +// advanced version comparisons +mod version_req; diff --git a/src/rust/vendor/semver-0.9.0/src/version.rs b/src/rust/vendor/semver-0.9.0/src/version.rs new file mode 100644 index 000000000..38de13319 --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/src/version.rs @@ -0,0 +1,759 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The `version` module gives you tools to create and compare SemVer-compliant +//! versions. + +use std::cmp::{self, Ordering}; +use std::fmt; +use std::hash; +use std::error::Error; + +use std::result; +use std::str; + +use semver_parser; + +#[cfg(feature = "serde")] +use serde::ser::{Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde::de::{self, Deserialize, Deserializer, Visitor}; + +/// An identifier in the pre-release or build metadata. +/// +/// See sections 9 and 10 of the spec for more about pre-release identifers and +/// build metadata. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Identifier { + /// An identifier that's solely numbers. + Numeric(u64), + /// An identifier with letters and numbers. + AlphaNumeric(String), +} + +impl From for Identifier { + fn from(other: semver_parser::version::Identifier) -> Identifier { + match other { + semver_parser::version::Identifier::Numeric(n) => Identifier::Numeric(n), + semver_parser::version::Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(s), + } + } +} + +impl fmt::Display for Identifier { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Identifier::Numeric(ref n) => fmt::Display::fmt(n, f), + Identifier::AlphaNumeric(ref s) => fmt::Display::fmt(s, f), + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for Identifier { + fn serialize(&self, serializer: S) -> result::Result + where S: Serializer + { + // Serialize Identifier as a number or string. + match *self { + Identifier::Numeric(n) => serializer.serialize_u64(n), + Identifier::AlphaNumeric(ref s) => serializer.serialize_str(s), + } + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Identifier { + fn deserialize(deserializer: D) -> result::Result + where D: Deserializer<'de> + { + struct IdentifierVisitor; + + // Deserialize Identifier from a number or string. + impl<'de> Visitor<'de> for IdentifierVisitor { + type Value = Identifier; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a SemVer pre-release or build identifier") + } + + fn visit_u64(self, numeric: u64) -> result::Result + where E: de::Error + { + Ok(Identifier::Numeric(numeric)) + } + + fn visit_str(self, alphanumeric: &str) -> result::Result + where E: de::Error + { + Ok(Identifier::AlphaNumeric(alphanumeric.to_owned())) + } + } + + deserializer.deserialize_any(IdentifierVisitor) + } +} + +/// Represents a version number conforming to the semantic versioning scheme. +#[derive(Clone, Eq, Debug)] +pub struct Version { + /// The major version, to be incremented on incompatible changes. + pub major: u64, + /// The minor version, to be incremented when functionality is added in a + /// backwards-compatible manner. + pub minor: u64, + /// The patch version, to be incremented when backwards-compatible bug + /// fixes are made. + pub patch: u64, + /// The pre-release version identifier, if one exists. + pub pre: Vec, + /// The build metadata, ignored when determining version precedence. + pub build: Vec, +} + +impl From for Version { + fn from(other: semver_parser::version::Version) -> Version { + Version { + major: other.major, + minor: other.minor, + patch: other.patch, + pre: other.pre.into_iter().map(From::from).collect(), + build: other.build.into_iter().map(From::from).collect(), + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for Version { + fn serialize(&self, serializer: S) -> result::Result + where S: Serializer + { + // Serialize Version as a string. + serializer.collect_str(self) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Version { + fn deserialize(deserializer: D) -> result::Result + where D: Deserializer<'de> + { + struct VersionVisitor; + + // Deserialize Version from a string. + impl<'de> Visitor<'de> for VersionVisitor { + type Value = Version; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a SemVer version as a string") + } + + fn visit_str(self, v: &str) -> result::Result + where E: de::Error + { + Version::parse(v).map_err(de::Error::custom) + } + } + + deserializer.deserialize_str(VersionVisitor) + } +} + +/// An error type for this crate +/// +/// Currently, just a generic error. Will make this nicer later. +#[derive(Clone,PartialEq,Debug,PartialOrd)] +pub enum SemVerError { + /// An error ocurred while parsing. + ParseError(String), +} + +impl fmt::Display for SemVerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &SemVerError::ParseError(ref m) => write!(f, "{}", m), + } + } +} + +impl Error for SemVerError { + fn description(&self) -> &str { + match self { + &SemVerError::ParseError(ref m) => m, + } + } +} + +/// A Result type for errors +pub type Result = result::Result; + +impl Version { + + /// Contructs the simple case without pre or build. + pub fn new(major: u64, minor: u64, patch: u64) -> Version { + Version { + major: major, + minor: minor, + patch: patch, + pre: Vec::new(), + build: Vec::new() + } + } + + /// Parse a string into a semver object. + pub fn parse(version: &str) -> Result { + let res = semver_parser::version::parse(version); + + match res { + // Convert plain String error into proper ParseError + Err(e) => Err(SemVerError::ParseError(e)), + Ok(v) => Ok(From::from(v)), + } + } + + /// Clears the build metadata + fn clear_metadata(&mut self) { + self.build = Vec::new(); + self.pre = Vec::new(); + } + + /// Increments the patch number for this Version (Must be mutable) + pub fn increment_patch(&mut self) { + self.patch += 1; + self.clear_metadata(); + } + + /// Increments the minor version number for this Version (Must be mutable) + /// + /// As instructed by section 7 of the spec, the patch number is reset to 0. + pub fn increment_minor(&mut self) { + self.minor += 1; + self.patch = 0; + self.clear_metadata(); + } + + /// Increments the major version number for this Version (Must be mutable) + /// + /// As instructed by section 8 of the spec, the minor and patch numbers are + /// reset to 0 + pub fn increment_major(&mut self) { + self.major += 1; + self.minor = 0; + self.patch = 0; + self.clear_metadata(); + } + + /// Checks to see if the current Version is in pre-release status + pub fn is_prerelease(&self) -> bool { + !self.pre.is_empty() + } +} + +impl str::FromStr for Version { + type Err = SemVerError; + + fn from_str(s: &str) -> Result { + Version::parse(s) + } +} + +impl fmt::Display for Version { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); + if !self.pre.is_empty() { + try!(write!(f, "-")); + for (i, x) in self.pre.iter().enumerate() { + if i != 0 { + try!(write!(f, ".")) + } + try!(write!(f, "{}", x)); + } + } + if !self.build.is_empty() { + try!(write!(f, "+")); + for (i, x) in self.build.iter().enumerate() { + if i != 0 { + try!(write!(f, ".")) + } + try!(write!(f, "{}", x)); + } + } + Ok(()) + } +} + +impl cmp::PartialEq for Version { + #[inline] + fn eq(&self, other: &Version) -> bool { + // We should ignore build metadata here, otherwise versions v1 and v2 + // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which + // violate strict total ordering rules. + self.major == other.major && self.minor == other.minor && self.patch == other.patch && + self.pre == other.pre + } +} + +impl cmp::PartialOrd for Version { + fn partial_cmp(&self, other: &Version) -> Option { + Some(self.cmp(other)) + } +} + +impl cmp::Ord for Version { + fn cmp(&self, other: &Version) -> Ordering { + match self.major.cmp(&other.major) { + Ordering::Equal => {} + r => return r, + } + + match self.minor.cmp(&other.minor) { + Ordering::Equal => {} + r => return r, + } + + match self.patch.cmp(&other.patch) { + Ordering::Equal => {} + r => return r, + } + + // NB: semver spec says 0.0.0-pre < 0.0.0 + // but the version of ord defined for vec + // says that [] < [pre] so we alter it here + match (self.pre.len(), other.pre.len()) { + (0, 0) => Ordering::Equal, + (0, _) => Ordering::Greater, + (_, 0) => Ordering::Less, + (_, _) => self.pre.cmp(&other.pre), + } + } +} + +impl hash::Hash for Version { + fn hash(&self, into: &mut H) { + self.major.hash(into); + self.minor.hash(into); + self.patch.hash(into); + self.pre.hash(into); + } +} + +impl From<(u64,u64,u64)> for Version { + fn from(tuple: (u64,u64,u64)) -> Version { + let (major, minor, patch) = tuple; + Version::new(major, minor, patch) + } +} + +#[cfg(test)] +mod tests { + use std::result; + use super::Version; + use super::Identifier; + use super::SemVerError; + + #[test] + fn test_parse() { + fn parse_error(e: &str) -> result::Result { + return Err(SemVerError::ParseError(e.to_string())); + } + + assert_eq!(Version::parse(""), + parse_error("Error parsing major identifier")); + assert_eq!(Version::parse(" "), + parse_error("Error parsing major identifier")); + assert_eq!(Version::parse("1"), + parse_error("Expected dot")); + assert_eq!(Version::parse("1.2"), + parse_error("Expected dot")); + assert_eq!(Version::parse("1.2.3-"), + parse_error("Error parsing prerelease")); + assert_eq!(Version::parse("a.b.c"), + parse_error("Error parsing major identifier")); + assert_eq!(Version::parse("1.2.3 abc"), + parse_error("Extra junk after valid version: abc")); + + assert_eq!(Version::parse("1.2.3"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + + assert_eq!(Version::parse("1.2.3"), + Ok(Version::new(1,2,3))); + + assert_eq!(Version::parse(" 1.2.3 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + assert_eq!(Version::parse("1.2.3-alpha1"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!(Version::parse(" 1.2.3-alpha1 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!(Version::parse("1.2.3+build5"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse(" 1.2.3+build5 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse("1.2.3-alpha1+build5"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse(" 1.2.3-alpha1+build5 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::Numeric(1), + Identifier::AlphaNumeric(String::from("alpha1")), + Identifier::Numeric(9), + ], + build: vec![Identifier::AlphaNumeric(String::from("build5")), + Identifier::Numeric(7), + Identifier::AlphaNumeric(String::from("3aedf")), + ], + })); + assert_eq!(Version::parse("0.4.0-beta.1+0851523"), + Ok(Version { + major: 0, + minor: 4, + patch: 0, + pre: vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1), + ], + build: vec![Identifier::AlphaNumeric(String::from("0851523"))], + })); + + } + + #[test] + fn test_increment_patch() { + let mut buggy_release = Version::parse("0.1.0").unwrap(); + buggy_release.increment_patch(); + assert_eq!(buggy_release, Version::parse("0.1.1").unwrap()); + } + + #[test] + fn test_increment_minor() { + let mut feature_release = Version::parse("1.4.6").unwrap(); + feature_release.increment_minor(); + assert_eq!(feature_release, Version::parse("1.5.0").unwrap()); + } + + #[test] + fn test_increment_major() { + let mut chrome_release = Version::parse("46.1.246773").unwrap(); + chrome_release.increment_major(); + assert_eq!(chrome_release, Version::parse("47.0.0").unwrap()); + } + + #[test] + fn test_increment_keep_prerelease() { + let mut release = Version::parse("1.0.0-alpha").unwrap(); + release.increment_patch(); + + assert_eq!(release, Version::parse("1.0.1").unwrap()); + + release.increment_minor(); + + assert_eq!(release, Version::parse("1.1.0").unwrap()); + + release.increment_major(); + + assert_eq!(release, Version::parse("2.0.0").unwrap()); + } + + + #[test] + fn test_increment_clear_metadata() { + let mut release = Version::parse("1.0.0+4442").unwrap(); + release.increment_patch(); + + assert_eq!(release, Version::parse("1.0.1").unwrap()); + release = Version::parse("1.0.1+hello").unwrap(); + + release.increment_minor(); + + assert_eq!(release, Version::parse("1.1.0").unwrap()); + release = Version::parse("1.1.3747+hello").unwrap(); + + release.increment_major(); + + assert_eq!(release, Version::parse("2.0.0").unwrap()); + } + + #[test] + fn test_eq() { + assert_eq!(Version::parse("1.2.3"), Version::parse("1.2.3")); + assert_eq!(Version::parse("1.2.3-alpha1"), + Version::parse("1.2.3-alpha1")); + assert_eq!(Version::parse("1.2.3+build.42"), + Version::parse("1.2.3+build.42")); + assert_eq!(Version::parse("1.2.3-alpha1+42"), + Version::parse("1.2.3-alpha1+42")); + assert_eq!(Version::parse("1.2.3+23"), Version::parse("1.2.3+42")); + } + + #[test] + fn test_ne() { + assert!(Version::parse("0.0.0") != Version::parse("0.0.1")); + assert!(Version::parse("0.0.0") != Version::parse("0.1.0")); + assert!(Version::parse("0.0.0") != Version::parse("1.0.0")); + assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); + } + + #[test] + fn test_show() { + assert_eq!(format!("{}", Version::parse("1.2.3").unwrap()), + "1.2.3".to_string()); + assert_eq!(format!("{}", Version::parse("1.2.3-alpha1").unwrap()), + "1.2.3-alpha1".to_string()); + assert_eq!(format!("{}", Version::parse("1.2.3+build.42").unwrap()), + "1.2.3+build.42".to_string()); + assert_eq!(format!("{}", Version::parse("1.2.3-alpha1+42").unwrap()), + "1.2.3-alpha1+42".to_string()); + } + + #[test] + fn test_to_string() { + assert_eq!(Version::parse("1.2.3").unwrap().to_string(), + "1.2.3".to_string()); + assert_eq!(Version::parse("1.2.3-alpha1").unwrap().to_string(), + "1.2.3-alpha1".to_string()); + assert_eq!(Version::parse("1.2.3+build.42").unwrap().to_string(), + "1.2.3+build.42".to_string()); + assert_eq!(Version::parse("1.2.3-alpha1+42").unwrap().to_string(), + "1.2.3-alpha1+42".to_string()); + } + + #[test] + fn test_lt() { + assert!(Version::parse("0.0.0") < Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.0.0") < Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.0") < Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3")); + assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3-alpha2")); + assert!(!(Version::parse("1.2.3-alpha2") < Version::parse("1.2.3-alpha2"))); + assert!(!(Version::parse("1.2.3+23") < Version::parse("1.2.3+42"))); + } + + #[test] + fn test_le() { + assert!(Version::parse("0.0.0") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.0.0") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.0") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3-alpha1") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3-alpha2") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3+23") <= Version::parse("1.2.3+42")); + } + + #[test] + fn test_gt() { + assert!(Version::parse("1.2.3-alpha2") > Version::parse("0.0.0")); + assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.0.0")); + assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); + assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha1")); + assert!(Version::parse("1.2.3") > Version::parse("1.2.3-alpha2")); + assert!(!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha2"))); + assert!(!(Version::parse("1.2.3+23") > Version::parse("1.2.3+42"))); + } + + #[test] + fn test_ge() { + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("0.0.0")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.0.0")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.0")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha1")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3+23") >= Version::parse("1.2.3+42")); + } + + #[test] + fn test_prerelease_check() { + assert!(Version::parse("1.0.0").unwrap().is_prerelease() == false); + assert!(Version::parse("0.0.1").unwrap().is_prerelease() == false); + assert!(Version::parse("4.1.4-alpha").unwrap().is_prerelease()); + assert!(Version::parse("1.0.0-beta294296").unwrap().is_prerelease()); + } + + #[test] + fn test_spec_order() { + let vs = ["1.0.0-alpha", + "1.0.0-alpha.1", + "1.0.0-alpha.beta", + "1.0.0-beta", + "1.0.0-beta.2", + "1.0.0-beta.11", + "1.0.0-rc.1", + "1.0.0"]; + let mut i = 1; + while i < vs.len() { + let a = Version::parse(vs[i - 1]); + let b = Version::parse(vs[i]); + assert!(a < b, "nope {:?} < {:?}", a, b); + i += 1; + } + } + + #[test] + fn test_from_str() { + assert_eq!("1.2.3".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + assert_eq!(" 1.2.3 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + assert_eq!("1.2.3-alpha1".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!(" 1.2.3-alpha1 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!("1.2.3+build5".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(" 1.2.3+build5 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!("1.2.3-alpha1+build5".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(" 1.2.3-alpha1+build5 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!("1.2.3-1.alpha1.9+build5.7.3aedf ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::Numeric(1), + Identifier::AlphaNumeric(String::from("alpha1")), + Identifier::Numeric(9), + ], + build: vec![Identifier::AlphaNumeric(String::from("build5")), + Identifier::Numeric(7), + Identifier::AlphaNumeric(String::from("3aedf")), + ], + })); + assert_eq!("0.4.0-beta.1+0851523".parse(), + Ok(Version { + major: 0, + minor: 4, + patch: 0, + pre: vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1), + ], + build: vec![Identifier::AlphaNumeric(String::from("0851523"))], + })); + + } + + #[test] + fn test_from_str_errors() { + fn parse_error(e: &str) -> result::Result { + return Err(SemVerError::ParseError(e.to_string())); + } + + assert_eq!("".parse(), parse_error("Error parsing major identifier")); + assert_eq!(" ".parse(), parse_error("Error parsing major identifier")); + assert_eq!("1".parse(), parse_error("Expected dot")); + assert_eq!("1.2".parse(), + parse_error("Expected dot")); + assert_eq!("1.2.3-".parse(), + parse_error("Error parsing prerelease")); + assert_eq!("a.b.c".parse(), + parse_error("Error parsing major identifier")); + assert_eq!("1.2.3 abc".parse(), + parse_error("Extra junk after valid version: abc")); + } +} diff --git a/src/rust/vendor/semver-0.9.0/src/version_req.rs b/src/rust/vendor/semver-0.9.0/src/version_req.rs new file mode 100644 index 000000000..6e6a542b8 --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/src/version_req.rs @@ -0,0 +1,895 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::error::Error; +use std::fmt; +use std::result; +use std::str; + +use Version; +use version::Identifier; +use semver_parser; + +#[cfg(feature = "serde")] +use serde::ser::{Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde::de::{self, Deserialize, Deserializer, Visitor}; + +use self::Op::{Ex, Gt, GtEq, Lt, LtEq, Tilde, Compatible, Wildcard}; +use self::WildcardVersion::{Major, Minor, Patch}; +use self::ReqParseError::*; + +/// A `VersionReq` is a struct containing a list of predicates that can apply to ranges of version +/// numbers. Matching operations can then be done with the `VersionReq` against a particular +/// version to see if it satisfies some or all of the constraints. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct VersionReq { + predicates: Vec, +} + +impl From for VersionReq { + fn from(other: semver_parser::range::VersionReq) -> VersionReq { + VersionReq { predicates: other.predicates.into_iter().map(From::from).collect() } + } +} + +#[cfg(feature = "serde")] +impl Serialize for VersionReq { + fn serialize(&self, serializer: S) -> result::Result + where S: Serializer + { + // Serialize VersionReq as a string. + serializer.collect_str(self) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for VersionReq { + fn deserialize(deserializer: D) -> result::Result + where D: Deserializer<'de> + { + struct VersionReqVisitor; + + /// Deserialize `VersionReq` from a string. + impl<'de> Visitor<'de> for VersionReqVisitor { + type Value = VersionReq; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a SemVer version requirement as a string") + } + + fn visit_str(self, v: &str) -> result::Result + where E: de::Error + { + VersionReq::parse(v).map_err(de::Error::custom) + } + } + + deserializer.deserialize_str(VersionReqVisitor) + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +enum WildcardVersion { + Major, + Minor, + Patch, +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +enum Op { + Ex, // Exact + Gt, // Greater than + GtEq, // Greater than or equal to + Lt, // Less than + LtEq, // Less than or equal to + Tilde, // e.g. ~1.0.0 + Compatible, // compatible by definition of semver, indicated by ^ + Wildcard(WildcardVersion), // x.y.*, x.*, * +} + +impl From for Op { + fn from(other: semver_parser::range::Op) -> Op { + use semver_parser::range; + match other { + range::Op::Ex => Op::Ex, + range::Op::Gt => Op::Gt, + range::Op::GtEq => Op::GtEq, + range::Op::Lt => Op::Lt, + range::Op::LtEq => Op::LtEq, + range::Op::Tilde => Op::Tilde, + range::Op::Compatible => Op::Compatible, + range::Op::Wildcard(version) => { + match version { + range::WildcardVersion::Major => Op::Wildcard(WildcardVersion::Major), + range::WildcardVersion::Minor => Op::Wildcard(WildcardVersion::Minor), + range::WildcardVersion::Patch => Op::Wildcard(WildcardVersion::Patch), + } + } + } + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +struct Predicate { + op: Op, + major: u64, + minor: Option, + patch: Option, + pre: Vec, +} + +impl From for Predicate { + fn from(other: semver_parser::range::Predicate) -> Predicate { + Predicate { + op: From::from(other.op), + major: other.major, + minor: other.minor, + patch: other.patch, + pre: other.pre.into_iter().map(From::from).collect(), + } + } +} + +/// A `ReqParseError` is returned from methods which parse a string into a `VersionReq`. Each +/// enumeration is one of the possible errors that can occur. +#[derive(Clone, Debug, PartialEq)] +pub enum ReqParseError { + /// The given version requirement is invalid. + InvalidVersionRequirement, + /// You have already provided an operation, such as `=`, `~`, or `^`. Only use one. + OpAlreadySet, + /// The sigil you have written is not correct. + InvalidSigil, + /// All components of a version must be numeric. + VersionComponentsMustBeNumeric, + /// There was an error parsing an identifier. + InvalidIdentifier, + /// At least a major version is required. + MajorVersionRequired, + /// An unimplemented version requirement. + UnimplementedVersionRequirement, + /// This form of requirement is deprecated. + DeprecatedVersionRequirement(VersionReq), +} + +impl fmt::Display for ReqParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for ReqParseError { + fn description(&self) -> &str { + match self { + &InvalidVersionRequirement => "the given version requirement is invalid", + &OpAlreadySet => { + "you have already provided an operation, such as =, ~, or ^; only use one" + }, + &InvalidSigil => "the sigil you have written is not correct", + &VersionComponentsMustBeNumeric => "version components must be numeric", + &InvalidIdentifier => "invalid identifier", + &MajorVersionRequired => "at least a major version number is required", + &UnimplementedVersionRequirement => { + "the given version requirement is not implemented, yet" + }, + &DeprecatedVersionRequirement(_) => "This requirement is deprecated", + } + } +} + +impl From for ReqParseError { + fn from(other: String) -> ReqParseError { + match &*other { + "Null is not a valid VersionReq" => ReqParseError::InvalidVersionRequirement, + "VersionReq did not parse properly." => ReqParseError::OpAlreadySet, + _ => ReqParseError::InvalidVersionRequirement, + } + } +} + +impl VersionReq { + /// `any()` is a factory method which creates a `VersionReq` with no constraints. In other + /// words, any version will match against it. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// + /// let anything = VersionReq::any(); + /// ``` + pub fn any() -> VersionReq { + VersionReq { predicates: vec![] } + } + + /// `parse()` is the main constructor of a `VersionReq`. It takes a string like `"^1.2.3"` + /// and turns it into a `VersionReq` that matches that particular constraint. + /// + /// A `Result` is returned which contains a `ReqParseError` if there was a problem parsing the + /// `VersionReq`. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// + /// let version = VersionReq::parse("=1.2.3"); + /// let version = VersionReq::parse(">1.2.3"); + /// let version = VersionReq::parse("<1.2.3"); + /// let version = VersionReq::parse("~1.2.3"); + /// let version = VersionReq::parse("^1.2.3"); + /// let version = VersionReq::parse("1.2.3"); // synonym for ^1.2.3 + /// let version = VersionReq::parse("<=1.2.3"); + /// let version = VersionReq::parse(">=1.2.3"); + /// ``` + /// + /// This example demonstrates error handling, and will panic. + /// + /// ```should-panic + /// use semver::VersionReq; + /// + /// let version = match VersionReq::parse("not a version") { + /// Ok(version) => version, + /// Err(e) => panic!("There was a problem parsing: {}", e), + /// } + /// ``` + pub fn parse(input: &str) -> Result { + let res = semver_parser::range::parse(input); + + if let Ok(v) = res { + return Ok(From::from(v)); + } + + return match VersionReq::parse_deprecated(input) { + Some(v) => { + Err(ReqParseError::DeprecatedVersionRequirement(v)) + } + None => Err(From::from(res.err().unwrap())), + } + } + + fn parse_deprecated(version: &str) -> Option { + return match version { + ".*" => Some(VersionReq::any()), + "0.1.0." => Some(VersionReq::parse("0.1.0").unwrap()), + "0.3.1.3" => Some(VersionReq::parse("0.3.13").unwrap()), + "0.2*" => Some(VersionReq::parse("0.2.*").unwrap()), + "*.0" => Some(VersionReq::any()), + _ => None, + } + } + + /// `exact()` is a factory method which creates a `VersionReq` with one exact constraint. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// use semver::Version; + /// + /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] }; + /// let exact = VersionReq::exact(&version); + /// ``` + pub fn exact(version: &Version) -> VersionReq { + VersionReq { predicates: vec![Predicate::exact(version)] } + } + + /// `matches()` matches a given `Version` against this `VersionReq`. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// use semver::Version; + /// + /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] }; + /// let exact = VersionReq::exact(&version); + /// + /// assert!(exact.matches(&version)); + /// ``` + pub fn matches(&self, version: &Version) -> bool { + // no predicates means anything matches + if self.predicates.is_empty() { + return true; + } + + self.predicates.iter().all(|p| p.matches(version)) && + self.predicates.iter().any(|p| p.pre_tag_is_compatible(version)) + } +} + +impl str::FromStr for VersionReq { + type Err = ReqParseError; + + fn from_str(s: &str) -> Result { + VersionReq::parse(s) + } +} + +impl Predicate { + fn exact(version: &Version) -> Predicate { + Predicate { + op: Ex, + major: version.major, + minor: Some(version.minor), + patch: Some(version.patch), + pre: version.pre.clone(), + } + } + + /// `matches()` takes a `Version` and determines if it matches this particular `Predicate`. + pub fn matches(&self, ver: &Version) -> bool { + match self.op { + Ex => self.is_exact(ver), + Gt => self.is_greater(ver), + GtEq => self.is_exact(ver) || self.is_greater(ver), + Lt => !self.is_exact(ver) && !self.is_greater(ver), + LtEq => !self.is_greater(ver), + Tilde => self.matches_tilde(ver), + Compatible => self.is_compatible(ver), + Wildcard(_) => self.matches_wildcard(ver), + } + } + + fn is_exact(&self, ver: &Version) -> bool { + if self.major != ver.major { + return false; + } + + match self.minor { + Some(minor) => { + if minor != ver.minor { + return false; + } + } + None => return true, + } + + match self.patch { + Some(patch) => { + if patch != ver.patch { + return false; + } + } + None => return true, + } + + if self.pre != ver.pre { + return false; + } + + true + } + + // https://docs.npmjs.com/misc/semver#prerelease-tags + fn pre_tag_is_compatible(&self, ver: &Version) -> bool { + // If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will + // only be + // allowed to satisfy comparator sets if at least one comparator with the same + // [major, + // minor, patch] tuple also has a prerelease tag. + !ver.is_prerelease() || + (self.major == ver.major && self.minor == Some(ver.minor) && + self.patch == Some(ver.patch) && !self.pre.is_empty()) + } + + fn is_greater(&self, ver: &Version) -> bool { + if self.major != ver.major { + return ver.major > self.major; + } + + match self.minor { + Some(minor) => { + if minor != ver.minor { + return ver.minor > minor; + } + } + None => return false, + } + + match self.patch { + Some(patch) => { + if patch != ver.patch { + return ver.patch > patch; + } + } + None => return false, + } + + if !self.pre.is_empty() { + return ver.pre.is_empty() || ver.pre > self.pre; + } + + false + } + + // see https://www.npmjs.org/doc/misc/semver.html for behavior + fn matches_tilde(&self, ver: &Version) -> bool { + let minor = match self.minor { + Some(n) => n, + None => return self.major == ver.major, + }; + + match self.patch { + Some(patch) => { + self.major == ver.major && minor == ver.minor && + (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver))) + } + None => self.major == ver.major && minor == ver.minor, + } + } + + // see https://www.npmjs.org/doc/misc/semver.html for behavior + fn is_compatible(&self, ver: &Version) -> bool { + if self.major != ver.major { + return false; + } + + let minor = match self.minor { + Some(n) => n, + None => return self.major == ver.major, + }; + + match self.patch { + Some(patch) => { + if self.major == 0 { + if minor == 0 { + ver.minor == minor && ver.patch == patch && self.pre_is_compatible(ver) + } else { + ver.minor == minor && + (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver))) + } + } else { + ver.minor > minor || + (ver.minor == minor && + (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver)))) + } + } + None => { + if self.major == 0 { + ver.minor == minor + } else { + ver.minor >= minor + } + } + } + } + + fn pre_is_compatible(&self, ver: &Version) -> bool { + ver.pre.is_empty() || ver.pre >= self.pre + } + + // see https://www.npmjs.org/doc/misc/semver.html for behavior + fn matches_wildcard(&self, ver: &Version) -> bool { + match self.op { + Wildcard(Major) => true, + Wildcard(Minor) => self.major == ver.major, + Wildcard(Patch) => { + match self.minor { + Some(minor) => self.major == ver.major && minor == ver.minor, + None => { + // minor and patch version astericks mean match on major + self.major == ver.major + } + } + } + _ => false, // unreachable + } + } +} + +impl fmt::Display for VersionReq { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if self.predicates.is_empty() { + try!(write!(fmt, "*")); + } else { + for (i, ref pred) in self.predicates.iter().enumerate() { + if i == 0 { + try!(write!(fmt, "{}", pred)); + } else { + try!(write!(fmt, ", {}", pred)); + } + } + } + + Ok(()) + } +} + +impl fmt::Display for Predicate { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.op { + Wildcard(Major) => try!(write!(fmt, "*")), + Wildcard(Minor) => try!(write!(fmt, "{}.*", self.major)), + Wildcard(Patch) => { + if let Some(minor) = self.minor { + try!(write!(fmt, "{}.{}.*", self.major, minor)) + } else { + try!(write!(fmt, "{}.*.*", self.major)) + } + } + _ => { + try!(write!(fmt, "{}{}", self.op, self.major)); + + match self.minor { + Some(v) => try!(write!(fmt, ".{}", v)), + None => (), + } + + match self.patch { + Some(v) => try!(write!(fmt, ".{}", v)), + None => (), + } + + if !self.pre.is_empty() { + try!(write!(fmt, "-")); + for (i, x) in self.pre.iter().enumerate() { + if i != 0 { + try!(write!(fmt, ".")) + } + try!(write!(fmt, "{}", x)); + } + } + } + } + + Ok(()) + } +} + +impl fmt::Display for Op { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Ex => try!(write!(fmt, "= ")), + Gt => try!(write!(fmt, "> ")), + GtEq => try!(write!(fmt, ">= ")), + Lt => try!(write!(fmt, "< ")), + LtEq => try!(write!(fmt, "<= ")), + Tilde => try!(write!(fmt, "~")), + Compatible => try!(write!(fmt, "^")), + // gets handled specially in Predicate::fmt + Wildcard(_) => try!(write!(fmt, "")), + } + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::{VersionReq, Op}; + use super::super::version::Version; + use std::hash::{Hash, Hasher}; + + fn req(s: &str) -> VersionReq { + VersionReq::parse(s).unwrap() + } + + fn version(s: &str) -> Version { + match Version::parse(s) { + Ok(v) => v, + Err(e) => panic!("`{}` is not a valid version. Reason: {:?}", s, e), + } + } + + fn assert_match(req: &VersionReq, vers: &[&str]) { + for ver in vers.iter() { + assert!(req.matches(&version(*ver)), "did not match {}", ver); + } + } + + fn assert_not_match(req: &VersionReq, vers: &[&str]) { + for ver in vers.iter() { + assert!(!req.matches(&version(*ver)), "matched {}", ver); + } + } + + fn calculate_hash(t: T) -> u64 { + use std::collections::hash_map::DefaultHasher; + + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_parsing_default() { + let r = req("1.0.0"); + + assert_eq!(r.to_string(), "^1.0.0".to_string()); + + assert_match(&r, &["1.0.0", "1.0.1"]); + assert_not_match(&r, &["0.9.9", "0.10.0", "0.1.0"]); + } + + #[test] + fn test_parsing_exact() { + let r = req("=1.0.0"); + + assert!(r.to_string() == "= 1.0.0".to_string()); + assert_eq!(r.to_string(), "= 1.0.0".to_string()); + + assert_match(&r, &["1.0.0"]); + assert_not_match(&r, &["1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"]); + + let r = req("=0.9.0"); + + assert_eq!(r.to_string(), "= 0.9.0".to_string()); + + assert_match(&r, &["0.9.0"]); + assert_not_match(&r, &["0.9.1", "1.9.0", "0.0.9"]); + + let r = req("=0.1.0-beta2.a"); + + assert_eq!(r.to_string(), "= 0.1.0-beta2.a".to_string()); + + assert_match(&r, &["0.1.0-beta2.a"]); + assert_not_match(&r, &["0.9.1", "0.1.0", "0.1.1-beta2.a", "0.1.0-beta2"]); + } + + #[test] + fn test_parse_metadata_see_issue_88_see_issue_88() { + for op in &[Op::Compatible, Op::Ex, Op::Gt, Op::GtEq, Op::Lt, Op::LtEq, Op::Tilde] { + req(&format!("{} 1.2.3+meta", op)); + } + } + + #[test] + pub fn test_parsing_greater_than() { + let r = req(">= 1.0.0"); + + assert_eq!(r.to_string(), ">= 1.0.0".to_string()); + + assert_match(&r, &["1.0.0", "2.0.0"]); + assert_not_match(&r, &["0.1.0", "0.0.1", "1.0.0-pre", "2.0.0-pre"]); + + let r = req(">= 2.1.0-alpha2"); + + assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha3", "2.1.0", "3.0.0"]); + assert_not_match(&r, + &["2.0.0", "2.1.0-alpha1", "2.0.0-alpha2", "3.0.0-alpha2"]); + } + + #[test] + pub fn test_parsing_less_than() { + let r = req("< 1.0.0"); + + assert_eq!(r.to_string(), "< 1.0.0".to_string()); + + assert_match(&r, &["0.1.0", "0.0.1"]); + assert_not_match(&r, &["1.0.0", "1.0.0-beta", "1.0.1", "0.9.9-alpha"]); + + let r = req("<= 2.1.0-alpha2"); + + assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha1", "2.0.0", "1.0.0"]); + assert_not_match(&r, + &["2.1.0", "2.2.0-alpha1", "2.0.0-alpha2", "1.0.0-alpha2"]); + } + + #[test] + pub fn test_multiple() { + let r = req("> 0.0.9, <= 2.5.3"); + assert_eq!(r.to_string(), "> 0.0.9, <= 2.5.3".to_string()); + assert_match(&r, &["0.0.10", "1.0.0", "2.5.3"]); + assert_not_match(&r, &["0.0.8", "2.5.4"]); + + let r = req("0.3.0, 0.4.0"); + assert_eq!(r.to_string(), "^0.3.0, ^0.4.0".to_string()); + assert_not_match(&r, &["0.0.8", "0.3.0", "0.4.0"]); + + let r = req("<= 0.2.0, >= 0.5.0"); + assert_eq!(r.to_string(), "<= 0.2.0, >= 0.5.0".to_string()); + assert_not_match(&r, &["0.0.8", "0.3.0", "0.5.1"]); + + let r = req("0.1.0, 0.1.4, 0.1.6"); + assert_eq!(r.to_string(), "^0.1.0, ^0.1.4, ^0.1.6".to_string()); + assert_match(&r, &["0.1.6", "0.1.9"]); + assert_not_match(&r, &["0.1.0", "0.1.4", "0.2.0"]); + + assert!(VersionReq::parse("> 0.1.0,").is_err()); + assert!(VersionReq::parse("> 0.3.0, ,").is_err()); + + let r = req(">=0.5.1-alpha3, <0.6"); + assert_eq!(r.to_string(), ">= 0.5.1-alpha3, < 0.6".to_string()); + assert_match(&r, + &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]); + assert_not_match(&r, + &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"]); + assert_not_match(&r, &["0.6.0", "0.6.0-pre"]); + } + + #[test] + pub fn test_parsing_tilde() { + let r = req("~1"); + assert_match(&r, &["1.0.0", "1.0.1", "1.1.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "0.0.9"]); + + let r = req("~1.2"); + assert_match(&r, &["1.2.0", "1.2.1"]); + assert_not_match(&r, &["1.1.1", "1.3.0", "0.0.9"]); + + let r = req("~1.2.2"); + assert_match(&r, &["1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.2.1", "1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + + let r = req("~1.2.3-beta.2"); + assert_match(&r, &["1.2.3", "1.2.4", "1.2.3-beta.2", "1.2.3-beta.4"]); + assert_not_match(&r, &["1.3.3", "1.1.4", "1.2.3-beta.1", "1.2.4-beta.2"]); + } + + #[test] + pub fn test_parsing_compatible() { + let r = req("^1"); + assert_match(&r, &["1.1.2", "1.1.0", "1.2.1", "1.0.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "0.1.4"]); + assert_not_match(&r, &["1.0.0-beta1", "0.1.0-alpha", "1.0.1-pre"]); + + let r = req("^1.1"); + assert_match(&r, &["1.1.2", "1.1.0", "1.2.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.0.1", "0.1.4"]); + + let r = req("^1.1.2"); + assert_match(&r, &["1.1.2", "1.1.4", "1.2.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]); + assert_not_match(&r, &["1.1.2-alpha1", "1.1.3-alpha1", "2.9.0-alpha1"]); + + let r = req("^0.1.2"); + assert_match(&r, &["0.1.2", "0.1.4"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]); + assert_not_match(&r, &["0.1.2-beta", "0.1.3-alpha", "0.2.0-pre"]); + + let r = req("^0.5.1-alpha3"); + assert_match(&r, + &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]); + assert_not_match(&r, + &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre", "0.6.0"]); + + let r = req("^0.0.2"); + assert_match(&r, &["0.0.2"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1", "0.1.4"]); + + let r = req("^0.0"); + assert_match(&r, &["0.0.2", "0.0.0"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.1.4"]); + + let r = req("^0"); + assert_match(&r, &["0.9.1", "0.0.2", "0.0.0"]); + assert_not_match(&r, &["2.9.0", "1.1.1"]); + + let r = req("^1.4.2-beta.5"); + assert_match(&r, + &["1.4.2", "1.4.3", "1.4.2-beta.5", "1.4.2-beta.6", "1.4.2-c"]); + assert_not_match(&r, + &["0.9.9", "2.0.0", "1.4.2-alpha", "1.4.2-beta.4", "1.4.3-beta.5"]); + } + + #[test] + pub fn test_parsing_wildcard() { + let r = req(""); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + let r = req("*"); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + let r = req("x"); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + let r = req("X"); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + + let r = req("1.*"); + assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]); + assert_not_match(&r, &["0.0.9"]); + let r = req("1.x"); + assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]); + assert_not_match(&r, &["0.0.9"]); + let r = req("1.X"); + assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]); + assert_not_match(&r, &["0.0.9"]); + + let r = req("1.2.*"); + assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + let r = req("1.2.x"); + assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + let r = req("1.2.X"); + assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + } + + #[test] + pub fn test_any() { + let r = VersionReq::any(); + assert_match(&r, &["0.0.1", "0.1.0", "1.0.0"]); + } + + #[test] + pub fn test_pre() { + let r = req("=2.1.1-really.0"); + assert_match(&r, &["2.1.1-really.0"]); + } + + // #[test] + // pub fn test_parse_errors() { + // assert_eq!(Err(InvalidVersionRequirement), VersionReq::parse("\0")); + // assert_eq!(Err(OpAlreadySet), VersionReq::parse(">= >= 0.0.2")); + // assert_eq!(Err(InvalidSigil), VersionReq::parse(">== 0.0.2")); + // assert_eq!(Err(VersionComponentsMustBeNumeric), + // VersionReq::parse("a.0.0")); + // assert_eq!(Err(InvalidIdentifier), VersionReq::parse("1.0.0-")); + // assert_eq!(Err(MajorVersionRequired), VersionReq::parse(">=")); + // } + + #[test] + pub fn test_from_str() { + assert_eq!("1.0.0".parse::().unwrap().to_string(), + "^1.0.0".to_string()); + assert_eq!("=1.0.0".parse::().unwrap().to_string(), + "= 1.0.0".to_string()); + assert_eq!("~1".parse::().unwrap().to_string(), + "~1".to_string()); + assert_eq!("~1.2".parse::().unwrap().to_string(), + "~1.2".to_string()); + assert_eq!("^1".parse::().unwrap().to_string(), + "^1".to_string()); + assert_eq!("^1.1".parse::().unwrap().to_string(), + "^1.1".to_string()); + assert_eq!("*".parse::().unwrap().to_string(), + "*".to_string()); + assert_eq!("1.*".parse::().unwrap().to_string(), + "1.*".to_string()); + assert_eq!("< 1.0.0".parse::().unwrap().to_string(), + "< 1.0.0".to_string()); + } + + // #[test] + // pub fn test_from_str_errors() { + // assert_eq!(Err(InvalidVersionRequirement), "\0".parse::()); + // assert_eq!(Err(OpAlreadySet), ">= >= 0.0.2".parse::()); + // assert_eq!(Err(InvalidSigil), ">== 0.0.2".parse::()); + // assert_eq!(Err(VersionComponentsMustBeNumeric), + // "a.0.0".parse::()); + // assert_eq!(Err(InvalidIdentifier), "1.0.0-".parse::()); + // assert_eq!(Err(MajorVersionRequired), ">=".parse::()); + // } + + #[test] + fn test_cargo3202() { + let v = "0.*.*".parse::().unwrap(); + assert_eq!("0.*.*", format!("{}", v.predicates[0])); + + let v = "0.0.*".parse::().unwrap(); + assert_eq!("0.0.*", format!("{}", v.predicates[0])); + + let r = req("0.*.*"); + assert_match(&r, &["0.5.0"]); + } + + #[test] + fn test_eq_hash() { + assert!(req("^1") == req("^1")); + assert!(calculate_hash(req("^1")) == calculate_hash(req("^1"))); + assert!(req("^1") != req("^2")); + } + + #[test] + fn test_ordering() { + assert!(req("=1") < req("*")); + assert!(req(">1") < req("*")); + assert!(req(">=1") < req("*")); + assert!(req("<1") < req("*")); + assert!(req("<=1") < req("*")); + assert!(req("~1") < req("*")); + assert!(req("^1") < req("*")); + assert!(req("*") == req("*")); + } +} diff --git a/src/rust/vendor/semver-0.9.0/tests/deprecation.rs b/src/rust/vendor/semver-0.9.0/tests/deprecation.rs new file mode 100644 index 000000000..a5f533a34 --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/tests/deprecation.rs @@ -0,0 +1,22 @@ +extern crate semver; + +#[test] +fn test_regressions() { + use semver::VersionReq; + use semver::ReqParseError; + + let versions = vec![ + (".*", VersionReq::any()), + ("0.1.0.", VersionReq::parse("0.1.0").unwrap()), + ("0.3.1.3", VersionReq::parse("0.3.13").unwrap()), + ("0.2*", VersionReq::parse("0.2.*").unwrap()), + ("*.0", VersionReq::any()), + ]; + + for (version, requirement) in versions.into_iter() { + let parsed = VersionReq::parse(version); + let error = parsed.err().unwrap(); + + assert_eq!(ReqParseError::DeprecatedVersionRequirement(requirement), error); + } +} diff --git a/src/rust/vendor/semver-0.9.0/tests/regression.rs b/src/rust/vendor/semver-0.9.0/tests/regression.rs new file mode 100644 index 000000000..ef568a7d3 --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/tests/regression.rs @@ -0,0 +1,25 @@ +extern crate semver; +extern crate crates_index; +extern crate tempdir; + +// This test checks to see if every existing crate parses successfully. Important to not break the +// Rust universe! + +#[cfg(feature = "ci")] +#[test] +fn test_regressions() { + use tempdir::TempDir; + use crates_index::Index; + use semver::Version; + + let dir = TempDir::new("semver").unwrap(); + let index = Index::new(dir.into_path()); + index.clone().unwrap(); + + for krate in index.crates() { + for version in krate.versions() { + let v = version.version(); + assert!(Version::parse(v).is_ok(), "failed: {} ({})", version.name(), v); + } + } +} diff --git a/src/rust/vendor/semver-0.9.0/tests/serde.rs b/src/rust/vendor/semver-0.9.0/tests/serde.rs new file mode 100644 index 000000000..bcb92643c --- /dev/null +++ b/src/rust/vendor/semver-0.9.0/tests/serde.rs @@ -0,0 +1,90 @@ +#![cfg(feature = "serde")] + +#[macro_use] +extern crate serde_derive; + +extern crate semver; +extern crate serde_json; + +use semver::{Identifier, Version, VersionReq}; + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +struct Identified { + name: String, + identifier: Identifier, +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +struct Versioned { + name: String, + vers: Version, +} + +#[test] +fn serialize_identifier() { + let id = Identified { + name: "serde".to_owned(), + identifier: Identifier::Numeric(100), + }; + let j = serde_json::to_string(&id).unwrap(); + assert_eq!(j, r#"{"name":"serde","identifier":100}"#); + + let id = Identified { + name: "serde".to_owned(), + identifier: Identifier::AlphaNumeric("b100".to_owned()), + }; + let j = serde_json::to_string(&id).unwrap(); + assert_eq!(j, r#"{"name":"serde","identifier":"b100"}"#); +} + +#[test] +fn deserialize_identifier() { + let j = r#"{"name":"serde","identifier":100}"#; + let id = serde_json::from_str::(j).unwrap(); + let expected = Identified { + name: "serde".to_owned(), + identifier: Identifier::Numeric(100), + }; + assert_eq!(id, expected); + + let j = r#"{"name":"serde","identifier":"b100"}"#; + let id = serde_json::from_str::(j).unwrap(); + let expected = Identified { + name: "serde".to_owned(), + identifier: Identifier::AlphaNumeric("b100".to_owned()), + }; + assert_eq!(id, expected); +} + +#[test] +fn serialize_version() { + let v = Versioned { + name: "serde".to_owned(), + vers: Version::parse("1.0.0").unwrap(), + }; + let j = serde_json::to_string(&v).unwrap(); + assert_eq!(j, r#"{"name":"serde","vers":"1.0.0"}"#); +} + +#[test] +fn deserialize_version() { + let j = r#"{"name":"serde","vers":"1.0.0"}"#; + let v = serde_json::from_str::(j).unwrap(); + let expected = Versioned { + name: "serde".to_owned(), + vers: Version::parse("1.0.0").unwrap(), + }; + assert_eq!(v, expected); +} + +#[test] +fn serialize_versionreq() { + let v = VersionReq::exact(&Version::parse("1.0.0").unwrap()); + + assert_eq!(serde_json::to_string(&v).unwrap(), r#""= 1.0.0""#); +} + +#[test] +fn deserialize_versionreq() { + assert_eq!("1.0.0".parse::().unwrap(), serde_json::from_str(r#""1.0.0""#).unwrap()); +} diff --git a/src/rust/vendor/semver-parser/.cargo-checksum.json b/src/rust/vendor/semver-parser/.cargo-checksum.json new file mode 100644 index 000000000..73575fe27 --- /dev/null +++ b/src/rust/vendor/semver-parser/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"67597114802114d2a7fdb457c1cf5f7e0c951b21e287c6a47b9a86b9028cf64d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"d38feaa4f9468cd1e0ece22e0ad2eadfe6195a9a0a3843b7c722d5c7d81804fb","src/common.rs":"dc42336abd34e19ca9f732f33657e106f98dcc8c10d4c2564bc4f160cb31926e","src/lib.rs":"3ac8ef5a280344a25cb18ac386034c0fee8d64060fa14af5e25ed49f0cb2fd9e","src/range.rs":"3596f048d466d43887aff1e8c8c834476672a4627631ed35379c35466b5f02ec","src/recognize.rs":"9f16eda9fcd7d8af7eee4c3b89c611bd648040273fde6b35778f8a50b004c8b1","src/version.rs":"dbd91a4e4fd92a0aa9eb4f858ecbc1ecd680aa60572cc2ad2085e5c5c30e5b77"},"package":"388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"} \ No newline at end of file diff --git a/src/rust/vendor/semver-parser/Cargo.toml b/src/rust/vendor/semver-parser/Cargo.toml new file mode 100644 index 000000000..c2be8783d --- /dev/null +++ b/src/rust/vendor/semver-parser/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "semver-parser" +version = "0.7.0" +authors = ["Steve Klabnik "] +license = "MIT/Apache-2.0" +repository = "https://github.com/steveklabnik/semver-parser" +homepage = "https://github.com/steveklabnik/semver-parser" +documentation = "https://docs.rs/semver-parser" +description = """ +Parsing of the semver spec. +""" diff --git a/src/rust/vendor/semver-parser/LICENSE-APACHE b/src/rust/vendor/semver-parser/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/semver-parser/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/semver-parser/LICENSE-MIT b/src/rust/vendor/semver-parser/LICENSE-MIT new file mode 100644 index 000000000..fb7494ab8 --- /dev/null +++ b/src/rust/vendor/semver-parser/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Steve Klabnik + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/semver-parser/src/common.rs b/src/rust/vendor/semver-parser/src/common.rs new file mode 100644 index 000000000..267b4d92f --- /dev/null +++ b/src/rust/vendor/semver-parser/src/common.rs @@ -0,0 +1,66 @@ +use version::Identifier; +use recognize::{Recognize, Alt, OneOrMore, Inclusive, OneByte}; +use std::str::from_utf8; + +// by the time we get here, we know that it's all valid characters, so this doesn't need to return +// a result or anything +fn parse_meta(s: &str) -> Vec { + // Originally, I wanted to implement this method via calling parse, but parse is tolerant of + // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not + // numeric. So the strategy is to check with a recognizer first, and then call parse once + // we've determined that it's a number without a leading zero. + s.split(".") + .map(|part| { + // another wrinkle: we made sure that any number starts with a + // non-zero. But there's a problem: an actual zero is a number, yet + // gets left out by this heuristic. So let's also check for the + // single, lone zero. + if is_alpha_numeric(part) { + Identifier::AlphaNumeric(part.to_string()) + } else { + // we can unwrap here because we know it is only digits due to the regex + Identifier::Numeric(part.parse().unwrap()) + } + }).collect() +} + +// parse optional metadata (preceded by the prefix character) +pub fn parse_optional_meta(s: &[u8], prefix_char: u8)-> Result<(Vec, usize), String> { + if let Some(len) = prefix_char.p(s) { + let start = len; + if let Some(len) = letters_numbers_dash_dot(&s[start..]) { + let end = start + len; + Ok((parse_meta(from_utf8(&s[start..end]).unwrap()), end)) + } else { + Err("Error parsing prerelease".to_string()) + } + } else { + Ok((Vec::new(), 0)) + } +} + +pub fn is_alpha_numeric(s: &str) -> bool { + if let Some((_val, len)) = numeric_identifier(s.as_bytes()) { + // Return true for number with leading zero + // Note: doing it this way also handily makes overflow fail over. + len != s.len() + } else { + true + } +} + +// Note: could plumb overflow error up to return value as Result +pub fn numeric_identifier(s: &[u8]) -> Option<(u64, usize)> { + if let Some(len) = Alt(b'0', OneOrMore(Inclusive(b'0'..b'9'))).p(s) { + from_utf8(&s[0..len]).unwrap().parse().ok().map(|val| (val, len)) + } else { + None + } +} + +pub fn letters_numbers_dash_dot(s: &[u8]) -> Option { + OneOrMore(OneByte(|c| c == b'-' || c == b'.' || + (b'0' <= c && c <= b'9') || + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z'))).p(s) +} diff --git a/src/rust/vendor/semver-parser/src/lib.rs b/src/rust/vendor/semver-parser/src/lib.rs new file mode 100644 index 000000000..3b0d8f051 --- /dev/null +++ b/src/rust/vendor/semver-parser/src/lib.rs @@ -0,0 +1,8 @@ +pub mod version; +pub mod range; + +// for private stuff the two share +mod common; + +// for recognizer combinators +mod recognize; diff --git a/src/rust/vendor/semver-parser/src/range.rs b/src/rust/vendor/semver-parser/src/range.rs new file mode 100644 index 000000000..858be9fbc --- /dev/null +++ b/src/rust/vendor/semver-parser/src/range.rs @@ -0,0 +1,696 @@ +use common::{self, numeric_identifier, letters_numbers_dash_dot}; +use version::Identifier; +use std::str::{FromStr, from_utf8}; +use recognize::*; + +#[derive(Debug)] +pub struct VersionReq { + pub predicates: Vec, +} + +#[derive(PartialEq,Debug)] +pub enum WildcardVersion { + Major, + Minor, + Patch, +} + +#[derive(PartialEq,Debug)] +pub enum Op { + Ex, // Exact + Gt, // Greater than + GtEq, // Greater than or equal to + Lt, // Less than + LtEq, // Less than or equal to + Tilde, // e.g. ~1.0.0 + Compatible, // compatible by definition of semver, indicated by ^ + Wildcard(WildcardVersion), // x.y.*, x.*, * +} + +impl FromStr for Op { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "=" => Ok(Op::Ex), + ">" => Ok(Op::Gt), + ">=" => Ok(Op::GtEq), + "<" => Ok(Op::Lt), + "<=" => Ok(Op::LtEq), + "~" => Ok(Op::Tilde), + "^" => Ok(Op::Compatible), + _ => Err(String::from("Could not parse Op")), + } + } +} + +#[derive(PartialEq,Debug)] +pub struct Predicate { + pub op: Op, + pub major: u64, + pub minor: Option, + pub patch: Option, + pub pre: Vec, +} + +fn numeric_or_wild(s: &[u8]) -> Option<(Option, usize)> { + if let Some((val, len)) = numeric_identifier(s) { + Some((Some(val), len)) + } else if let Some(len) = OneOf(b"*xX").p(s) { + Some((None, len)) + } else { + None + } +} + +fn dot_numeric_or_wild(s: &[u8]) -> Option<(Option, usize)> { + b'.'.p(s).and_then(|len| + numeric_or_wild(&s[len..]).map(|(val, len2)| (val, len + len2)) + ) +} + +fn operation(s: &[u8]) -> Option<(Op, usize)> { + if let Some(len) = "=".p(s) { + Some((Op::Ex, len)) + } else if let Some(len) = ">=".p(s) { + Some((Op::GtEq, len)) + } else if let Some(len) = ">".p(s) { + Some((Op::Gt, len)) + } else if let Some(len) = "<=".p(s) { + Some((Op::LtEq, len)) + } else if let Some(len) = "<".p(s) { + Some((Op::Lt, len)) + } else if let Some(len) = "~".p(s) { + Some((Op::Tilde, len)) + } else if let Some(len) = "^".p(s) { + Some((Op::Compatible, len)) + } else { + None + } +} + +fn whitespace(s: &[u8]) -> Option { + ZeroOrMore(OneOf(b"\t\r\n ")).p(s) +} + +pub fn parse_predicate(range: &str) -> Result { + let s = range.trim().as_bytes(); + let mut i = 0; + let mut operation = if let Some((op, len)) = operation(&s[i..]) { + i += len; + op + } else { + // operations default to Compatible + Op::Compatible + }; + if let Some(len) = whitespace.p(&s[i..]) { + i += len; + } + let major = if let Some((major, len)) = numeric_identifier(&s[i..]) { + i += len; + major + } else { + return Err("Error parsing major version number: ".to_string()); + }; + let minor = if let Some((minor, len)) = dot_numeric_or_wild(&s[i..]) { + i += len; + if minor.is_none() { + operation = Op::Wildcard(WildcardVersion::Minor); + } + minor + } else { + None + }; + let patch = if let Some((patch, len)) = dot_numeric_or_wild(&s[i..]) { + i += len; + if patch.is_none() { + operation = Op::Wildcard(WildcardVersion::Patch); + } + patch + } else { + None + }; + let (pre, pre_len) = common::parse_optional_meta(&s[i..], b'-')?; + i += pre_len; + if let Some(len) = (b'+', letters_numbers_dash_dot).p(&s[i..]) { + i += len; + } + if i != s.len() { + return Err("Extra junk after valid predicate: ".to_string() + + from_utf8(&s[i..]).unwrap()); + } + Ok(Predicate { + op: operation, + major: major, + minor: minor, + patch: patch, + pre: pre, + }) +} + +pub fn parse(ranges: &str) -> Result { + // null is an error + if ranges == "\0" { + return Err(String::from("Null is not a valid VersionReq")); + } + + // an empty range is a major version wildcard + // so is a lone * or x of either capitalization + if (ranges == "") + || (ranges == "*") + || (ranges == "x") + || (ranges == "X") { + return Ok(VersionReq { + predicates: vec![Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }], + }); + } + + + let ranges = ranges.trim(); + + let predicates: Result, String> = ranges + .split(",") + .map(|range| { + parse_predicate(range) + }) + .collect(); + + let predicates = try!(predicates); + + if predicates.len() == 0 { + return Err(String::from("VersionReq did not parse properly")); + } + + Ok(VersionReq { + predicates: predicates, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use range; + use version::Identifier; + + #[test] + fn test_parsing_default() { + let r = range::parse("1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_exact_01() { + let r = range::parse("=1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Ex, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_exact_02() { + let r = range::parse("=0.9.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Ex, + major: 0, + minor: Some(9), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_exact_03() { + let r = range::parse("=0.1.0-beta2.a").unwrap(); + + assert_eq!(Predicate { + op: Op::Ex, + major: 0, + minor: Some(1), + patch: Some(0), + pre: vec![Identifier::AlphaNumeric(String::from("beta2")), + Identifier::AlphaNumeric(String::from("a"))], + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_greater_than() { + let r = range::parse("> 1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Gt, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_greater_than_01() { + let r = range::parse(">= 1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_greater_than_02() { + let r = range::parse(">= 2.1.0-alpha2").unwrap(); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 2, + minor: Some(1), + patch: Some(0), + pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_less_than() { + let r = range::parse("< 1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Lt, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_less_than_eq() { + let r = range::parse("<= 2.1.0-alpha2").unwrap(); + + assert_eq!(Predicate { + op: Op::LtEq, + major: 2, + minor: Some(1), + patch: Some(0), + pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_tilde() { + let r = range::parse("~1").unwrap(); + + assert_eq!(Predicate { + op: Op::Tilde, + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_compatible() { + let r = range::parse("^0").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_blank() { + let r = range::parse("").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_wildcard() { + let r = range::parse("*").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_x() { + let r = range::parse("x").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_capital_x() { + let r = range::parse("X").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_minor_wildcard_star() { + let r = range::parse("1.*").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Minor), + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_minor_wildcard_x() { + let r = range::parse("1.x").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Minor), + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_minor_wildcard_capital_x() { + let r = range::parse("1.X").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Minor), + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_patch_wildcard_star() { + let r = range::parse("1.2.*").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Patch), + major: 1, + minor: Some(2), + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_patch_wildcard_x() { + let r = range::parse("1.2.x").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Patch), + major: 1, + minor: Some(2), + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_patch_wildcard_capital_x() { + let r = range::parse("1.2.X").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Patch), + major: 1, + minor: Some(2), + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_multiple_01() { + let r = range::parse("> 0.0.9, <= 2.5.3").unwrap(); + + assert_eq!(Predicate { + op: Op::Gt, + major: 0, + minor: Some(0), + patch: Some(9), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::LtEq, + major: 2, + minor: Some(5), + patch: Some(3), + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + pub fn test_multiple_02() { + let r = range::parse("0.3.0, 0.4.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(3), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(4), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + pub fn test_multiple_03() { + let r = range::parse("<= 0.2.0, >= 0.5.0").unwrap(); + + assert_eq!(Predicate { + op: Op::LtEq, + major: 0, + minor: Some(2), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 0, + minor: Some(5), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + pub fn test_multiple_04() { + let r = range::parse("0.1.0, 0.1.4, 0.1.6").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(1), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(1), + patch: Some(4), + pre: Vec::new(), + }, + r.predicates[1] + ); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(1), + patch: Some(6), + pre: Vec::new(), + }, + r.predicates[2] + ); + } + + #[test] + pub fn test_multiple_05() { + let r = range::parse(">=0.5.1-alpha3, <0.6").unwrap(); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 0, + minor: Some(5), + patch: Some(1), + pre: vec![Identifier::AlphaNumeric(String::from("alpha3"))], + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::Lt, + major: 0, + minor: Some(6), + patch: None, + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + fn test_parse_build_metadata_with_predicate() { + assert_eq!(range::parse("^1.2.3+meta").unwrap().predicates[0].op, + Op::Compatible); + assert_eq!(range::parse("~1.2.3+meta").unwrap().predicates[0].op, + Op::Tilde); + assert_eq!(range::parse("=1.2.3+meta").unwrap().predicates[0].op, + Op::Ex); + assert_eq!(range::parse("<=1.2.3+meta").unwrap().predicates[0].op, + Op::LtEq); + assert_eq!(range::parse(">=1.2.3+meta").unwrap().predicates[0].op, + Op::GtEq); + assert_eq!(range::parse("<1.2.3+meta").unwrap().predicates[0].op, + Op::Lt); + assert_eq!(range::parse(">1.2.3+meta").unwrap().predicates[0].op, + Op::Gt); + } + + #[test] + pub fn test_parse_errors() { + assert!(range::parse("\0").is_err()); + assert!(range::parse(">= >= 0.0.2").is_err()); + assert!(range::parse(">== 0.0.2").is_err()); + assert!(range::parse("a.0.0").is_err()); + assert!(range::parse("1.0.0-").is_err()); + assert!(range::parse(">=").is_err()); + assert!(range::parse("> 0.1.0,").is_err()); + assert!(range::parse("> 0.3.0, ,").is_err()); + } + + #[test] + pub fn test_large_major_version() { + assert!(range::parse("18446744073709551617.0.0").is_err()); + } + + #[test] + pub fn test_large_minor_version() { + assert!(range::parse("0.18446744073709551617.0").is_err()); + } + + #[test] + pub fn test_large_patch_version() { + assert!(range::parse("0.0.18446744073709551617").is_err()); + } +} diff --git a/src/rust/vendor/semver-parser/src/recognize.rs b/src/rust/vendor/semver-parser/src/recognize.rs new file mode 100644 index 000000000..c0dd771fc --- /dev/null +++ b/src/rust/vendor/semver-parser/src/recognize.rs @@ -0,0 +1,154 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Licensed under either of MIT or Apache License, Version 2.0, +// at your option. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Simple recognizer combinators. + +// This version is similar to a similar one in the "lang" module of +// xi-editor, but is stripped down to only the needed combinators. + +use std::ops; + +pub trait Recognize { + fn p(&self, s: &[u8]) -> Option; +} + +impl Option> Recognize for F { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + self(s) + } +} + +pub struct OneByte(pub F); + +impl bool> Recognize for OneByte { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + if s.is_empty() || !self.0(s[0]) { + None + } else { + Some(1) + } + } +} + +impl Recognize for u8 { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + OneByte(|b| b == *self).p(s) + } +} + +/// Use Inclusive(a..b) to indicate an inclusive range. When a...b syntax becomes +/// stable, we can get rid of this and switch to that. +pub struct Inclusive(pub T); + +impl Recognize for Inclusive> { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + OneByte(|x| x >= self.0.start && x <= self.0.end).p(s) + } +} + +impl<'a> Recognize for &'a [u8] { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + let len = self.len(); + if s.len() >= len && &s[..len] == *self { + Some(len) + } else { + None + } + } +} + +impl<'a> Recognize for &'a str { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + self.as_bytes().p(s) + } +} + +impl Recognize for (P1, P2) { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + self.0.p(s).and_then(|len1| + self.1.p(&s[len1..]).map(|len2| + len1 + len2)) + } +} + +/// Choice from two heterogeneous alternatives. +pub struct Alt(pub P1, pub P2); + +impl Recognize for Alt { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option { + self.0.p(s).or_else(|| self.1.p(s)) + } +} + +/// Choice from a homogenous slice of parsers. +pub struct OneOf<'a, P: 'a>(pub &'a [P]); + +impl<'a, P: Recognize> Recognize for OneOf<'a, P> { + #[inline] + fn p(&self, s: &[u8]) -> Option { + for ref p in self.0 { + if let Some(len) = p.p(s) { + return Some(len); + } + } + None + } +} + +pub struct OneOrMore

(pub P); + +impl Recognize for OneOrMore

{ + #[inline] + fn p(&self, s: &[u8]) -> Option { + let mut i = 0; + let mut count = 0; + while let Some(len) = self.0.p(&s[i..]) { + i += len; + count += 1; + } + if count >= 1 { + Some(i) + } else { + None + } + } +} + +pub struct ZeroOrMore

(pub P); + +impl Recognize for ZeroOrMore

{ + #[inline] + fn p(&self, s: &[u8]) -> Option { + let mut i = 0; + while let Some(len) = self.0.p(&s[i..]) { + i += len; + } + Some(i) + } +} diff --git a/src/rust/vendor/semver-parser/src/version.rs b/src/rust/vendor/semver-parser/src/version.rs new file mode 100644 index 000000000..570f94768 --- /dev/null +++ b/src/rust/vendor/semver-parser/src/version.rs @@ -0,0 +1,365 @@ +use std::fmt; +use std::str::from_utf8; + +use recognize::*; + +use common::{self, numeric_identifier}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Version { + pub major: u64, + pub minor: u64, + pub patch: u64, + pub pre: Vec, + pub build: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Identifier { + /// An identifier that's solely numbers. + Numeric(u64), + /// An identifier with letters and numbers. + AlphaNumeric(String), +} + +pub fn parse(version: &str) -> Result { + let s = version.trim().as_bytes(); + let mut i = 0; + let major = if let Some((major, len)) = numeric_identifier(&s[i..]) { + i += len; + major + } else { + return Err("Error parsing major identifier".to_string()); + }; + if let Some(len) = b'.'.p(&s[i..]) { + i += len; + } else { + return Err("Expected dot".to_string()); + } + let minor = if let Some((minor, len)) = numeric_identifier(&s[i..]) { + i += len; + minor + } else { + return Err("Error parsing minor identifier".to_string()); + }; + if let Some(len) = b'.'.p(&s[i..]) { + i += len; + } else { + return Err("Expected dot".to_string()); + } + let patch = if let Some((patch, len)) = numeric_identifier(&s[i..]) { + i += len; + patch + } else { + return Err("Error parsing patch identifier".to_string()); + }; + let (pre, pre_len) = common::parse_optional_meta(&s[i..], b'-')?; + i += pre_len; + let (build, build_len) = common::parse_optional_meta(&s[i..], b'+')?; + i += build_len; + if i != s.len() { + return Err("Extra junk after valid version: ".to_string() + + from_utf8(&s[i..]).unwrap()); + } + Ok(Version { + major: major, + minor: minor, + patch: patch, + pre: pre, + build: build, + }) +} + +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); + if !self.pre.is_empty() { + let strs: Vec<_> = + self.pre.iter().map(ToString::to_string).collect(); + try!(write!(f, "-{}", strs.join("."))); + } + if !self.build.is_empty() { + let strs: Vec<_> = + self.build.iter().map(ToString::to_string).collect(); + try!(write!(f, "+{}", strs.join("."))); + } + Ok(()) + } +} + +impl fmt::Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Identifier::Numeric(ref id) => id.fmt(f), + Identifier::AlphaNumeric(ref id) => id.fmt(f), + } + } +} + +#[cfg(test)] +mod tests { + use version; + use super::*; + + #[test] + fn parse_empty() { + let version = ""; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "empty string incorrectly considered a valid parse"); + } + + #[test] + fn parse_blank() { + let version = " "; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "blank string incorrectly considered a valid parse"); + } + + #[test] + fn parse_no_minor_patch() { + let version = "1"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_no_patch() { + let version = "1.2"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_empty_pre() { + let version = "1.2.3-"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_letters() { + let version = "a.b.c"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_with_letters() { + let version = "1.2.3 a.b.c"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_basic_version() { + let version = "1.2.3"; + + let parsed = version::parse(version).unwrap(); + + assert_eq!(1, parsed.major); + assert_eq!(2, parsed.minor); + assert_eq!(3, parsed.patch); + } + + #[test] + fn parse_trims_input() { + let version = " 1.2.3 "; + + let parsed = version::parse(version).unwrap(); + + assert_eq!(1, parsed.major); + assert_eq!(2, parsed.minor); + assert_eq!(3, parsed.patch); + } + + #[test] + fn parse_no_major_leading_zeroes() { + let version = "01.0.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "01 incorrectly considered a valid major version"); + } + + #[test] + fn parse_no_minor_leading_zeroes() { + let version = "0.01.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "01 incorrectly considered a valid minor version"); + } + + #[test] + fn parse_no_patch_leading_zeroes() { + let version = "0.0.01"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "01 incorrectly considered a valid patch version"); + } + + #[test] + fn parse_no_major_overflow() { + let version = "98765432109876543210.0.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid major version"); + } + + #[test] + fn parse_no_minor_overflow() { + let version = "0.98765432109876543210.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid minor version"); + } + + #[test] + fn parse_no_patch_overflow() { + let version = "0.0.98765432109876543210"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid patch version"); + } + + #[test] + fn parse_basic_prerelease() { + let version = "1.2.3-pre"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre"))]; + assert_eq!(expected_pre, parsed.pre); + } + + #[test] + fn parse_prerelease_alphanumeric() { + let version = "1.2.3-alpha1"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; + assert_eq!(expected_pre, parsed.pre); + } + + #[test] + fn parse_prerelease_zero() { + let version = "1.2.3-pre.0"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre")), + Identifier::Numeric(0)]; + assert_eq!(expected_pre, parsed.pre); + } + + #[test] + fn parse_basic_build() { + let version = "1.2.3+build"; + + let parsed = version::parse(version).unwrap(); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_build_alphanumeric() { + let version = "1.2.3+build5"; + + let parsed = version::parse(version).unwrap(); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_pre_and_build() { + let version = "1.2.3-alpha1+build5"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_complex_metadata_01() { + let version = "1.2.3-1.alpha1.9+build5.7.3aedf "; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::Numeric(1), + Identifier::AlphaNumeric(String::from("alpha1")), + Identifier::Numeric(9)]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build5")), + Identifier::Numeric(7), + Identifier::AlphaNumeric(String::from("3aedf"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_complex_metadata_02() { + let version = "0.4.0-beta.1+0851523"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1)]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("0851523"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_metadata_overflow() { + let version = "0.4.0-beta.1+98765432109876543210"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1)]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("98765432109876543210"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_regression_01() { + let version = "0.0.0-WIP"; + + let parsed = version::parse(version).unwrap(); + + assert_eq!(0, parsed.major); + assert_eq!(0, parsed.minor); + assert_eq!(0, parsed.patch); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("WIP"))]; + assert_eq!(expected_pre, parsed.pre); + } +} diff --git a/src/rust/vendor/ufmt-write/.cargo-checksum.json b/src/rust/vendor/ufmt-write/.cargo-checksum.json new file mode 100644 index 000000000..5403c4574 --- /dev/null +++ b/src/rust/vendor/ufmt-write/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"c8cb5b907495d7c398b900ae506da06148733ec73c70deb5e72dec422b48dc68","src/lib.rs":"0efe6a0124ca4abde04084f1d90e6055d49510717cd6fcaf09fba3d18d5a4b07"},"package":"e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"} \ No newline at end of file diff --git a/src/rust/vendor/ufmt-write/Cargo.toml b/src/rust/vendor/ufmt-write/Cargo.toml new file mode 100644 index 000000000..2609cb7de --- /dev/null +++ b/src/rust/vendor/ufmt-write/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "ufmt-write" +version = "0.1.0" +authors = ["Jorge Aparicio "] +description = "`μfmt`'s `uWrite` trait" +keywords = ["Debug", "Display", "Write", "format"] +categories = ["embedded", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/japaric/ufmt" + +[features] +std = [] diff --git a/src/rust/vendor/ufmt-write/src/lib.rs b/src/rust/vendor/ufmt-write/src/lib.rs new file mode 100644 index 000000000..cede77d56 --- /dev/null +++ b/src/rust/vendor/ufmt-write/src/lib.rs @@ -0,0 +1,48 @@ +//! `μfmt`'s `uWrite` trait + +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(missing_docs)] +#![deny(rust_2018_compatibility)] +#![deny(rust_2018_idioms)] +#![deny(warnings)] + +#[cfg(feature = "std")] +use core::convert::Infallible; + +#[allow(deprecated)] +unsafe fn uninitialized() -> T { + core::mem::uninitialized() +} + +/// A collection of methods that are required / used to format a message into a stream. +#[allow(non_camel_case_types)] +pub trait uWrite { + /// The error associated to this writer + type Error; + + /// Writes a string slice into this writer, returning whether the write succeeded. + /// + /// This method can only succeed if the entire string slice was successfully written, and this + /// method will not return until all data has been written or an error occurs. + fn write_str(&mut self, s: &str) -> Result<(), Self::Error>; + + /// Writes a [`char`] into this writer, returning whether the write succeeded. + /// + /// A single [`char`] may be encoded as more than one byte. This method can only succeed if the + /// entire byte sequence was successfully written, and this method will not return until all + /// data has been written or an error occurs. + fn write_char(&mut self, c: char) -> Result<(), Self::Error> { + let mut buf: [u8; 4] = unsafe { uninitialized() }; + self.write_str(c.encode_utf8(&mut buf)) + } +} + +#[cfg(feature = "std")] +impl uWrite for String { + type Error = Infallible; + + fn write_str(&mut self, s: &str) -> Result<(), Infallible> { + self.push_str(s); + Ok(()) + } +} diff --git a/src/rust/vendor/vcell/.cargo-checksum.json b/src/rust/vendor/vcell/.cargo-checksum.json new file mode 100644 index 000000000..cd3bcf6cd --- /dev/null +++ b/src/rust/vendor/vcell/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"e469fb3c433db7bac42b5bfc09283d50a56e1c317c0ace4c0f80f00df06578c4","Cargo.toml":"bde67021385af9ad0a2d682b0a6387e662d5475644b29a848609478ab9339878","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"035e70219855119df4273b3c5b97543ae82e0dd60c520416e759107c602f651b","README.md":"7c0eeea68cee21f8f1258f1937c70bbd228e120153ea3a2b2d9a77023452e448","src/lib.rs":"238ee7d12f7d44d0ae951bae2a9db28fc0d64a1f5f45d706dcbec73e3b598b96"},"package":"77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"} \ No newline at end of file diff --git a/src/rust/vendor/vcell/CHANGELOG.md b/src/rust/vendor/vcell/CHANGELOG.md new file mode 100644 index 000000000..520e34650 --- /dev/null +++ b/src/rust/vendor/vcell/CHANGELOG.md @@ -0,0 +1,34 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.1.3] - 2021-01-01 + +- Added `#[repr(transparent)]` to follow the `core::cell::Cell` + +## [v0.1.2] - 2019-08-29 + +### Added + +- Added back the `const-fn` feature, but unused for backward compatibility + +## [v0.1.1] - 2019-08-29 + +### Added + +- Added `.as_ptr()` +- `new()` now const by default + +## [v0.1.0] - 2017-03-08 + +- Initial release + +[Unreleased]: https://github.com/japaric/vcell/compare/v0.1.3...HEAD +[v0.1.3]: https://github.com/japaric/vcell/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/japaric/vcell/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/japaric/vcell/compare/v0.1.0...v0.1.1 diff --git a/src/rust/vendor/vcell/Cargo.toml b/src/rust/vendor/vcell/Cargo.toml new file mode 100644 index 000000000..050e4e0ac --- /dev/null +++ b/src/rust/vendor/vcell/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "vcell" +version = "0.1.3" +authors = ["Jorge Aparicio "] +description = "`Cell` with volatile read / write operations" +documentation = "https://docs.rs/vcell" +keywords = ["no-std", "volatile", "cell"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/japaric/vcell" + +[features] +const-fn = [] diff --git a/src/rust/vendor/vcell/LICENSE-APACHE b/src/rust/vendor/vcell/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/vcell/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/vcell/LICENSE-MIT b/src/rust/vendor/vcell/LICENSE-MIT new file mode 100644 index 000000000..a128ba402 --- /dev/null +++ b/src/rust/vendor/vcell/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/vcell/README.md b/src/rust/vendor/vcell/README.md new file mode 100644 index 000000000..29b02bd0a --- /dev/null +++ b/src/rust/vendor/vcell/README.md @@ -0,0 +1,27 @@ +[![crates.io](https://img.shields.io/crates/v/vcell.svg)](https://crates.io/crates/vcell) +[![crates.io](https://img.shields.io/crates/d/vcell.svg)](https://crates.io/crates/vcell) + +# `vcell` + +> Just like [`Cell`] but with [volatile] read / write operations + +[`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +[volatile]: https://doc.rust-lang.org/std/ptr/fn.read_volatile.html + +# [Change log](CHANGELOG.md) + +# License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/src/rust/vendor/vcell/src/lib.rs b/src/rust/vendor/vcell/src/lib.rs new file mode 100644 index 000000000..3512b5c6a --- /dev/null +++ b/src/rust/vendor/vcell/src/lib.rs @@ -0,0 +1,52 @@ +//! Just like [`Cell`] but with [volatile] read / write operations +//! +//! [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +//! [volatile]: https://doc.rust-lang.org/std/ptr/fn.read_volatile.html + +#![deny(missing_docs)] +#![deny(warnings)] +#![no_std] + +use core::cell::UnsafeCell; +use core::ptr; + +/// Just like [`Cell`] but with [volatile] read / write operations +/// +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [volatile]: https://doc.rust-lang.org/std/ptr/fn.read_volatile.html +#[repr(transparent)] +pub struct VolatileCell { + value: UnsafeCell, +} + +impl VolatileCell { + /// Creates a new `VolatileCell` containing the given value + pub const fn new(value: T) -> Self { + VolatileCell { value: UnsafeCell::new(value) } + } + + /// Returns a copy of the contained value + #[inline(always)] + pub fn get(&self) -> T + where T: Copy + { + unsafe { ptr::read_volatile(self.value.get()) } + } + + /// Sets the contained value + #[inline(always)] + pub fn set(&self, value: T) + where T: Copy + { + unsafe { ptr::write_volatile(self.value.get(), value) } + } + + /// Returns a raw pointer to the underlying data in the cell + #[inline(always)] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } +} + +// NOTE implicit because of `UnsafeCell` +// unsafe impl !Sync for VolatileCell {} diff --git a/src/rust/vendor/void/.cargo-checksum.json b/src/rust/vendor/void/.cargo-checksum.json new file mode 100644 index 000000000..9554bcd9d --- /dev/null +++ b/src/rust/vendor/void/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"ea686f87a150a8e43c4b7db57c56d3eda2a4963420d5570d91d99d7d610dd3fb","README.md":"f85783a6fcf9ecc19edabd710775a88430d9e886f46728bfd7d65cef55ff3e73","src/lib.rs":"7ab8269f30715c0729b0e04e5a09be4c413664dc4b530746ea3240ac80a64c66"},"package":"6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"} \ No newline at end of file diff --git a/src/rust/vendor/void/Cargo.toml b/src/rust/vendor/void/Cargo.toml new file mode 100644 index 000000000..1a031396a --- /dev/null +++ b/src/rust/vendor/void/Cargo.toml @@ -0,0 +1,15 @@ +[package] + +name = "void" +version = "1.0.2" +authors = ["Jonathan Reem "] +repository = "https://github.com/reem/rust-void.git" +description = "The uninhabited void type for use in statically impossible cases." +readme = "README.md" +license = "MIT" + +[features] + +default = ["std"] +std = [] + diff --git a/src/rust/vendor/void/README.md b/src/rust/vendor/void/README.md new file mode 100644 index 000000000..4f86c21cc --- /dev/null +++ b/src/rust/vendor/void/README.md @@ -0,0 +1,39 @@ +# Void + +> The uninhabited void type for use in statically impossible cases. + +## [Documentation](https://crates.fyi/crates/void/1.0.1) + +The uninhabited type, `enum Void { }` is useful in dealing with cases you +know to be impossible. For instance, if you are implementing a trait which +allows for error checking, but your case always succeeds, you can mark the +error case or type as `Void`, signaling to the compiler it can never happen. + +This crate also comes packed with a few traits offering extension methods to +`Result` and `Result`. + +## Usage + +Use the crates.io repository; add this to your `Cargo.toml` along +with the rest of your dependencies: + +```toml +[dependencies] +void = "1" +``` + +Then, use `Void` in your crate: + +```rust +extern crate void; +use void::Void; +``` + +## Author + +[Jonathan Reem](https://medium.com/@jreem) is the primary author and maintainer of void. + +## License + +MIT + diff --git a/src/rust/vendor/void/src/lib.rs b/src/rust/vendor/void/src/lib.rs new file mode 100644 index 000000000..3b6287c1b --- /dev/null +++ b/src/rust/vendor/void/src/lib.rs @@ -0,0 +1,121 @@ +#![cfg_attr(test, deny(warnings))] +#![deny(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +//! # Void +//! +//! The uninhabited void type for use in statically impossible cases. +//! +//! In its own crate so all the users in the ecosystem can share the same type. +//! This crate also comes ready with several extension traits for Result that add +//! extra functionality to `Result` and `Result`. +//! + +#[cfg(not(feature = "std"))] +mod coreprovider { + extern crate core; + pub use core::{fmt, cmp}; +} + +#[cfg(feature = "std")] +mod coreprovider { + pub use std::{fmt, cmp, error}; +} + +use coreprovider::*; + +/// The empty type for cases which can't occur. +#[derive(Copy)] +pub enum Void { } + +impl Clone for Void { + fn clone(&self) -> Void { + unreachable(*self) + } +} + +impl fmt::Debug for Void { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + unreachable(*self) + } +} + +impl fmt::Display for Void { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + unreachable(*self) + } +} + +impl cmp::PartialEq for Void { + fn eq(&self, _: &T) -> bool { + unreachable(*self) + } +} + +impl cmp::PartialOrd for Void { + fn partial_cmp(&self, _: &T) -> Option { + unreachable(*self) + } +} + +#[cfg(feature = "std")] +impl error::Error for Void { + fn description(&self) -> &str { + unreachable(*self) + } + + fn cause(&self) -> Option<&error::Error> { + unreachable(*self) + } +} + +/// A safe version of `intrinsincs::unreachable`. +/// +/// If this typechecks, anything that causes this to run is unreachable code. +/// +/// Calling this function in reachable code invokes undefined behavior, but +/// should not be possible unless `unsafe` was used elsewhere to construct +/// an instance of `Void` (which is already undefined behavior). +#[inline(always)] +pub fn unreachable(x: Void) -> ! { + match x {} +} + +/// Extensions to `Result` +pub trait ResultVoidExt: Sized { + /// Get the value out of a wrapper. + fn void_unwrap(self) -> T; +} + +impl ResultVoidExt for Result { + /// Get the value out of an always-ok Result. + /// + /// Never panics, since it is statically known to be Ok. + #[inline] + fn void_unwrap(self) -> T { + match self { + Ok(val) => val, + Err(e) => unreachable(e) + } + } +} + +/// Extensions to `Result` +pub trait ResultVoidErrExt: Sized { + /// Get the error out of a wrapper. + fn void_unwrap_err(self) -> E; +} + +impl ResultVoidErrExt for Result { + /// Get the error out of an always-err Result. + /// + /// Never panics, since it is statically known to be Err. + #[inline] + fn void_unwrap_err(self) -> E { + match self { + Ok(v) => unreachable(v), + Err(e) => e + } + } +} + diff --git a/src/rust/vendor/volatile-register/.cargo-checksum.json b/src/rust/vendor/volatile-register/.cargo-checksum.json new file mode 100644 index 000000000..1261a1148 --- /dev/null +++ b/src/rust/vendor/volatile-register/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"2ed0b4ea235d30f043cd2216c6ff83dde3669905b89a7230c7133523b950fde3","CODE_OF_CONDUCT.md":"fba7846e321b6ac7f74932cbf5831d89a7116c71763f1b263ba1c49ac7c2f382","Cargo.toml":"1818c565e31317a45efaf796fefa212b2c8aaef330cc2546fe1f5f6b0ba8f644","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0a633406531735659d570e7903394ec52f7707195a3c4af10279f06eec7acc76","README.md":"d2936b8b2345ac4685c4354c5627a413ec390354191bf0500f7ddb7645bdb8f2","src/lib.rs":"b193978a45a3c4d7a5f197ba7117a3bf9765abdd1ffc02d11abbed19490a5839"},"package":"de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"} \ No newline at end of file diff --git a/src/rust/vendor/volatile-register/CHANGELOG.md b/src/rust/vendor/volatile-register/CHANGELOG.md new file mode 100644 index 000000000..eaed582b6 --- /dev/null +++ b/src/rust/vendor/volatile-register/CHANGELOG.md @@ -0,0 +1,57 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.2.2] - 2023-10-20 + +### Changed + +- Added `#[repr(transparent)]` to `RO`, `RW`, and `WO` to ensure ABI + compatibility with underlying register. + +## [v0.2.1] - 2021-08-14 + +### Added + +- Added more docs.rs targets + +- The `modify` and `write` operations now take `&self`. + +- [breaking-change] `RO` and `RW` no longer implement `Sync`. This is required + to make the new `modify` and `write` sound. + +- [breaking-change] `RO`, `RW` and `WO` now require that the inner value be + `Copy`-able. + +- docs: remove "guarantee" about some operations being atomic as this crate may + be used in architectures different than the ARM Cortex-M. + +## [v0.1.2] - 2016-10-15 + +### Added + +- a (read-)`modify`(-write) method to `RW` + +## [v0.1.1] - 2016-09-27 + +### Added + +- Documentation link to Cargo metadata. + +## v0.1.0 - 2016-09-27 + +### Added + +- Read-Only (`RO`), Read-Write (`RW`) and Write-Only (`WO`) registers + +[Unreleased]: https://github.com/rust-embedded/volatile-register/compare/v0.2.2...HEAD +[v0.2.2]: https://github.com/rust-embedded/volatile-register/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-embedded/volatile-register/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-embedded/volatile-register/compare/v0.1.2...v0.2.0 +[v0.1.2]: https://github.com/rust-embedded/volatile-register/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-embedded/volatile-register/compare/v0.1.0...v0.1.1 diff --git a/src/rust/vendor/volatile-register/CODE_OF_CONDUCT.md b/src/rust/vendor/volatile-register/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..7a47646d0 --- /dev/null +++ b/src/rust/vendor/volatile-register/CODE_OF_CONDUCT.md @@ -0,0 +1,37 @@ +# The Rust Code of Conduct + +## Conduct + +**Contact**: [Libs team](https://github.com/rust-embedded/wg#the-libs-team) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Libs team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[team]: https://github.com/rust-embedded/wg#the-libs-team diff --git a/src/rust/vendor/volatile-register/Cargo.toml b/src/rust/vendor/volatile-register/Cargo.toml new file mode 100644 index 000000000..465220b68 --- /dev/null +++ b/src/rust/vendor/volatile-register/Cargo.toml @@ -0,0 +1,47 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "volatile-register" +version = "0.2.2" +authors = [ + "Jorge Aparicio ", + "Jonathan 'theJPster' Pallant ", +] +description = "Volatile access to memory mapped hardware registers" +documentation = "https://docs.rs/volatile-register" +readme = "README.md" +keywords = [ + "no-std", + "volatile", + "register", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-embedded/volatile-register" + +[package.metadata.docs.rs] +targets = [ + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "i686-unknown-linux-gnu", + "i686-pc-windows-msvc", + "thumbv8m.main-none-eabihf", + "thumbv6m-none-eabi", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", +] + +[dependencies.vcell] +version = "0.1.0" diff --git a/src/rust/vendor/volatile-register/LICENSE-APACHE b/src/rust/vendor/volatile-register/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/volatile-register/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/volatile-register/LICENSE-MIT b/src/rust/vendor/volatile-register/LICENSE-MIT new file mode 100644 index 000000000..a43445e6c --- /dev/null +++ b/src/rust/vendor/volatile-register/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/volatile-register/README.md b/src/rust/vendor/volatile-register/README.md new file mode 100644 index 000000000..bd69ff8aa --- /dev/null +++ b/src/rust/vendor/volatile-register/README.md @@ -0,0 +1,24 @@ +[![crates.io](https://img.shields.io/crates/d/volatile-register.svg)](https://crates.io/crates/volatile-register) +[![crates.io](https://img.shields.io/crates/v/volatile-register.svg)](https://crates.io/crates/volatile-register) + +# `volatile-register` + +> Volatile access to memory mapped hardware registers + +## [Documentation](https://docs.rs/crate/volatile-register) + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the +work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/src/rust/vendor/volatile-register/src/lib.rs b/src/rust/vendor/volatile-register/src/lib.rs new file mode 100644 index 000000000..5e89bdf98 --- /dev/null +++ b/src/rust/vendor/volatile-register/src/lib.rs @@ -0,0 +1,107 @@ +//! Volatile access to memory mapped hardware registers +//! +//! # Usage +//! +//! ``` no_run +//! use volatile_register::RW; +//! +//! // Create a struct that represents the memory mapped register block +//! /// Nested Vector Interrupt Controller +//! #[repr(C)] +//! pub struct Nvic { +//! /// Interrupt Set-Enable +//! pub iser: [RW; 8], +//! reserved0: [u32; 24], +//! /// Interrupt Clear-Enable +//! pub icer: [RW; 8], +//! reserved1: [u32; 24], +//! // .. more registers .. +//! } +//! +//! // Access the registers by casting the base address of the register block +//! // to the previously declared `struct` +//! let nvic = 0xE000_E100 as *const Nvic; +//! // Unsafe because the compiler can't verify the address is correct +//! unsafe { (*nvic).iser[0].write(1) } +//! ``` + +#![deny(missing_docs)] +#![no_std] + +extern crate vcell; + +use vcell::VolatileCell; + +/// Read-Only register +#[repr(transparent)] +pub struct RO + where T: Copy +{ + register: VolatileCell, +} + +impl RO + where T: Copy +{ + /// Reads the value of the register + #[inline(always)] + pub fn read(&self) -> T { + self.register.get() + } +} + +/// Read-Write register +#[repr(transparent)] +pub struct RW + where T: Copy +{ + register: VolatileCell, +} + +impl RW + where T: Copy +{ + /// Performs a read-modify-write operation + /// + /// NOTE: `unsafe` because writes to a register are side effectful + #[inline(always)] + pub unsafe fn modify(&self, f: F) + where F: FnOnce(T) -> T + { + self.register.set(f(self.register.get())); + } + + /// Reads the value of the register + #[inline(always)] + pub fn read(&self) -> T { + self.register.get() + } + + /// Writes a `value` into the register + /// + /// NOTE: `unsafe` because writes to a register are side effectful + #[inline(always)] + pub unsafe fn write(&self, value: T) { + self.register.set(value) + } +} + +/// Write-Only register +#[repr(transparent)] +pub struct WO + where T: Copy +{ + register: VolatileCell, +} + +impl WO + where T: Copy +{ + /// Writes `value` into the register + /// + /// NOTE: `unsafe` because writes to a register are side effectful + #[inline(always)] + pub unsafe fn write(&self, value: T) { + self.register.set(value) + } +} diff --git a/src/util.c b/src/util.c index 620d4ed34..d06e13a69 100644 --- a/src/util.c +++ b/src/util.c @@ -47,6 +47,16 @@ void util_uint8_to_hex(const uint8_t* in_bin, const size_t in_len, char* out) rust_util_bytes(in_bin, in_len), rust_util_bytes_mut((uint8_t*)out, in_len * 2 + 1)); } +const char* util_dbg_hex(const uint8_t* bin, const size_t len) +{ + if (len > UTIL_DBG_HEX_MAX_LEN) { + util_log("len too large, %zu > %d", len, UTIL_DBG_HEX_MAX_LEN); + } + static char buf[UTIL_DBG_HEX_MAX_LEN * 2 + 1] = {0}; + util_uint8_to_hex(bin, len, buf); + return buf; +} + void util_cleanup_str(char** str) { util_zero(*str, strlens(*str)); @@ -66,3 +76,25 @@ void util_cleanup_64(uint8_t** buf) { util_zero(*buf, 64); } + +// Max message size is MAX_LOG_LENGTH-1, becuase vsnprintf will always print a null character +#define MAX_LOG_LENGTH 101 + +void util_log(const char* fmt, ...) +{ +#if !defined(NDEBUG) + char buf[MAX_LOG_LENGTH] = ""; + + va_list va; + va_start(va, fmt); + int res = vsnprintf(buf, MAX_LOG_LENGTH, fmt, va); + va_end(va); + + rust_log(buf); + if (res > MAX_LOG_LENGTH - 1) { + rust_log("The complete log line didn't fit\n"); + } +#else + (void)fmt; +#endif +} diff --git a/src/util.h b/src/util.h index 90c65ce6c..e9fbd1e83 100644 --- a/src/util.h +++ b/src/util.h @@ -61,6 +61,22 @@ void util_zero(volatile void* dst, size_t len); // `out` must be of size in_len*2+1. Use BB_HEX_SIZE() to compute the size. void util_uint8_to_hex(const uint8_t* in_bin, size_t in_len, char* out); +#define UTIL_DBG_HEX_MAX_LEN 64 +/// This function is for debug purposes only! +/// +/// Don't use this in production, the returned pointer is only valid until this function is called +/// again. This function is not thread safe. +/// +/// Returns a null terminated string, suitable for printing with printf in C. +/// +/// Max `len` is UTIL_DBG_HEX_MAX_LEN. This function panics if `len` is to large. +/// +/// Usage: +/// uint8_t arr[2] = {1,2}; +/// util_log("%s", util_dbg_hex(arr, sizeof(arr))); +/// +const char* util_dbg_hex(const uint8_t* bin, size_t len); + #define BB_HEX_SIZE(in_bin) (sizeof((in_bin)) * 2 + 1) void util_cleanup_str(char** str); @@ -109,4 +125,6 @@ typedef struct { */ typedef enum { ASYNC_OP_TRUE, ASYNC_OP_FALSE, ASYNC_OP_NOT_READY } async_op_result_t; +void util_log(const char* fmt, ...) __attribute__((format(printf, 1, 2))); + #endif