rb-sys-0.9.97/.cargo_vcs_info.json0000644000000001530000000000100123600ustar { "git": { "sha1": "71a214816e4bd7dfc5620ae3dd07b4944d531dfb" }, "path_in_vcs": "crates/rb-sys" }rb-sys-0.9.97/Cargo.toml0000644000000034020000000000100103560ustar # 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.63" name = "rb-sys" version = "0.9.97" build = "build/main.rs" links = "rb" description = "Rust bindings for the CRuby API" homepage = "https://github.com/oxidize-rb/rb-sys" documentation = "https://docs.rs/rb-sys" readme = "readme.md" categories = ["external-ffi-bindings"] license = "MIT OR Apache-2.0" repository = "https://github.com/oxidize-rb/rb-sys" [lib] doctest = false [dev-dependencies.rusty-fork] version = "0.3.0" [build-dependencies.rb-sys-build] version = "0.9.97" [features] bindgen-deprecated-types = ["rb-sys-build/bindgen-deprecated-types"] bindgen-enable-function-attribute-detection = ["rb-sys-build/bindgen-enable-function-attribute-detection"] bindgen-impl-debug = ["rb-sys-build/bindgen-impl-debug"] bindgen-layout-tests = ["rb-sys-build/bindgen-layout-tests"] bindgen-rbimpls = ["rb-sys-build/bindgen-rbimpls"] bindgen-return-const-encoding-pointers = ["rb-sys-build/bindgen-return-const-encoding-pointers"] bindgen-sizet-is-usize = ["rb-sys-build/bindgen-sizet-is-usize"] default = [] fuzz = [] global-allocator = [] link-ruby = [] no-link-ruby = [] ruby-macros = ["stable-api"] ruby-static = [] stable-api = [] stable-api-compiled-fallback = ["stable-api"] stable-api-compiled-force = [] stable-api-compiled-testing = ["stable-api-compiled-fallback"] rb-sys-0.9.97/Cargo.toml.orig000064400000000000000000000030511046102023000140370ustar 00000000000000[package] build = "build/main.rs" name = "rb-sys" version = "0.9.97" edition = "2018" readme = "readme.md" categories = ["external-ffi-bindings"] description = "Rust bindings for the CRuby API" documentation = "https://docs.rs/rb-sys" homepage = "https://github.com/oxidize-rb/rb-sys" license = "MIT OR Apache-2.0" links = "rb" repository = "https://github.com/oxidize-rb/rb-sys" rust-version = "1.63" [build-dependencies] rb-sys-build = { version = "0.9.97", path = "../rb-sys-build" } [dev-dependencies] rb-sys = { path = ".", features = [ "link-ruby", "stable-api-compiled-fallback", ] } rusty-fork = "0.3.0" [features] default = [] link-ruby = [] fuzz = [] no-link-ruby = [] ruby-static = [] global-allocator = [] stable-api = [] stable-api-compiled-fallback = ["stable-api"] # Fallback to compiled C API stable-api-compiled-testing = [ "stable-api-compiled-fallback", ] # For testing the fallback in rb-sys (internal) stable-api-compiled-force = [] # Always use the compiled C API ruby-macros = ["stable-api"] # deprecated bindgen-rbimpls = ["rb-sys-build/bindgen-rbimpls"] bindgen-deprecated-types = ["rb-sys-build/bindgen-deprecated-types"] bindgen-layout-tests = ["rb-sys-build/bindgen-layout-tests"] bindgen-impl-debug = ["rb-sys-build/bindgen-impl-debug"] bindgen-sizet-is-usize = ["rb-sys-build/bindgen-sizet-is-usize"] bindgen-return-const-encoding-pointers = [ "rb-sys-build/bindgen-return-const-encoding-pointers", ] bindgen-enable-function-attribute-detection = [ "rb-sys-build/bindgen-enable-function-attribute-detection", ] [lib] doctest = false rb-sys-0.9.97/LICENSE-APACHE000064400000000000000000000250141046102023000130770ustar 00000000000000 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 Copyright 2021-2022 Ian Ker-Seymer 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. rb-sys-0.9.97/LICENSE-MIT000064400000000000000000000020761046102023000126120ustar 00000000000000The MIT License (MIT) Copyright (c) 2021-2022 Ian Ker-Seymer 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. rb-sys-0.9.97/bin/release.sh000075500000000000000000000011121046102023000136730ustar 00000000000000#!/bin/bash set -euo pipefail IFS=$'\n\t' if ! git diff-index --quiet HEAD --; then echo "There are git changes, cannot release" exit 1 fi read -rp "What version would you like to release? (current $(grep version Cargo.toml)): " version read -rp "Are you sure you want to bump to v$version? " prompt if [[ $prompt =~ [yY](es)* ]]; then sed -i '' "s/^version = .*/version = \"$version\"/g" Cargo.toml cargo build git add Cargo.lock Cargo.toml ../../Cargo.lock git commit -am "Bump to v$version" git tag "v$version" git push --atomic origin main "v$version" fi rb-sys-0.9.97/build/features.rs000064400000000000000000000056511046102023000144430ustar 00000000000000use rb_sys_build::{utils::is_mswin_or_mingw, RbConfig}; use crate::version::Version; pub fn is_global_allocator_enabled(rb_config: &RbConfig) -> bool { let (major, minor) = rb_config.major_minor(); let current_version = Version::new(major, minor); let two_four = Version::new(2, 4); let is_enabled = is_env_variable_defined("CARGO_FEATURE_GLOBAL_ALLOCATOR"); if current_version >= two_four { is_enabled } else { if is_enabled { eprintln!("WARN: The global allocator feature is only supported on Ruby 2.4+."); } false } } pub fn is_gem_enabled() -> bool { cfg!(rb_sys_gem) } pub fn is_no_link_ruby_enabled() -> bool { is_env_variable_defined("CARGO_FEATURE_NO_LINK_RUBY") } pub fn is_debug_build_enabled() -> bool { if is_linting() { return false; } println!("cargo:rerun-if-env-changed=RB_SYS_DEBUG_BUILD"); is_env_variable_defined("RB_SYS_DEBUG_BUILD") } pub fn is_ruby_static_enabled(rbconfig: &RbConfig) -> bool { println!("cargo:rerun-if-env-changed=RUBY_STATIC"); match std::env::var("RUBY_STATIC") { Ok(val) => val == "true" || val == "1", _ => { is_env_variable_defined("CARGO_FEATURE_RUBY_STATIC") || rbconfig.get("ENABLE_SHARED") == "no" } } } pub fn is_link_ruby_enabled() -> bool { if is_linting() { return false; } if is_no_link_ruby_enabled() { false } else if is_mswin_or_mingw() { true } else if is_gem_enabled() { if is_env_variable_defined("CARGO_FEATURE_LINK_RUBY") { let msg = " The `gem` and `link-ruby` features are mutually exclusive on this platform, since the libruby symbols will be available at runtime. If you for some reason want to dangerously link libruby for your gem (*not recommended*), you can remove the `gem` feature and add this to your `Cargo.toml`: [dependencies.rb-sys] features = [\"link-ruby\"] # Living dangerously! " .split('\n') .map(|line| line.trim()) .collect::>() .join("\n"); eprintln!("ERROR: {}", msg); std::process::exit(1); } else { false } } else { is_env_variable_defined("CARGO_FEATURE_LINK_RUBY") } } pub fn is_env_variable_defined(name: &str) -> bool { std::env::var(name).is_ok() } fn is_linting() -> bool { println!("cargo:rerun-if-env-changed=RUSTC_WRAPPER"); let clippy = match std::env::var_os("CARGO_CFG_FEATURE") { Some(val) => val.to_str().unwrap_or("").contains("clippy"), _ => false, }; let rust_analyzer = match std::env::var_os("RUSTC_WRAPPER") { Some(val) => val.to_str().unwrap_or("").contains("rust-analyzer"), _ => false, }; clippy || rust_analyzer } rb-sys-0.9.97/build/main.rs000064400000000000000000000167671046102023000135630ustar 00000000000000mod features; #[cfg(feature = "stable-api")] mod stable_api_config; mod version; use features::*; use rb_sys_build::{bindings, RbConfig}; use std::io::Write; use std::{ env, fs::{self, File}, path::PathBuf, }; use version::Version; const SUPPORTED_RUBY_VERSIONS: [Version; 9] = [ Version::new(2, 3), Version::new(2, 4), Version::new(2, 5), Version::new(2, 6), Version::new(2, 7), Version::new(3, 0), Version::new(3, 1), Version::new(3, 2), Version::new(3, 3), ]; fn main() { warn_deprecated_feature_flags(); let mut rbconfig = RbConfig::current(); let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let ruby_version = rbconfig.ruby_program_version(); let ruby_platform = rbconfig.platform(); let crate_version = env!("CARGO_PKG_VERSION"); let cfg_capture_path = out_dir.join(format!( "cfg-capture-{}-{}-{}", crate_version, ruby_platform, ruby_version )); let mut cfg_capture_file = File::create(cfg_capture_path).unwrap(); println!("cargo:rerun-if-env-changed=RUBY_ROOT"); println!("cargo:rerun-if-env-changed=RUBY_VERSION"); println!("cargo:rerun-if-env-changed=RUBY"); for file in fs::read_dir("build").unwrap() { println!("cargo:rerun-if-changed={}", file.unwrap().path().display()); } let bindings_path = bindings::generate( &rbconfig, is_ruby_static_enabled(&rbconfig), &mut cfg_capture_file, ) .expect("generate bindings"); println!("Bindings generated at: {}", bindings_path.display()); println!( "cargo:rustc-env=RB_SYS_BINDINGS_PATH={}", bindings_path.display() ); export_cargo_cfg(&mut rbconfig, &mut cfg_capture_file); #[cfg(feature = "stable-api")] stable_api_config::setup(Version::current(&rbconfig)).unwrap(); if is_link_ruby_enabled() { link_libruby(&mut rbconfig); } else { add_libruby_to_blocklist(&mut rbconfig); enable_dynamic_lookup(&mut rbconfig); } expose_cargo_features(&mut cfg_capture_file); add_unsupported_link_args_to_blocklist(&mut rbconfig); rbconfig.print_cargo_args(); if is_debug_build_enabled() { debug_and_exit(&mut rbconfig); } } macro_rules! cfg_capture { ($file:expr, $fmt:expr, $($arg:tt)*) => { println!($fmt, $($arg)*); writeln!($file, $fmt, $($arg)*).unwrap(); }; } fn add_unsupported_link_args_to_blocklist(rbconfig: &mut RbConfig) { rbconfig.blocklist_link_arg("-Wl,--compress-debug-sections=zlib"); rbconfig.blocklist_link_arg("-s"); } fn add_libruby_to_blocklist(rbconfig: &mut RbConfig) { rbconfig.blocklist_lib(&rbconfig.libruby_so_name()); rbconfig.blocklist_lib(&rbconfig.libruby_static_name()); } fn debug_and_exit(rbconfig: &mut RbConfig) { eprintln!("========== RbConfig\n"); dbg!(rbconfig); eprintln!("========== Environment Variables\n"); let env: std::collections::HashMap<_, _> = std::env::vars().collect(); dbg!(env); eprintln!("==========\n"); eprintln!("The \"RB_SYS_DEBUG_BUILD\" env var was set, aborting."); std::process::exit(1); } fn link_libruby(rbconfig: &mut RbConfig) { if is_link_ruby_enabled() { rbconfig.link_ruby(is_ruby_static_enabled(rbconfig)); } } fn export_cargo_cfg(rbconfig: &mut RbConfig, cap: &mut File) { rustc_cfg(rbconfig, "ruby_major", "MAJOR"); rustc_cfg(rbconfig, "ruby_minor", "MINOR"); rustc_cfg(rbconfig, "ruby_teeny", "TEENY"); rustc_cfg(rbconfig, "ruby_patchlevel", "PATCHLEVEL"); rustc_cfg(rbconfig, "ruby_api_version", "RUBY_API_VERSION"); if is_global_allocator_enabled(rbconfig) { println!("cargo:rustc-cfg=use_global_allocator"); } if is_gem_enabled() { println!("cargo:rustc-cfg=use_ruby_abi_version"); } if rbconfig.has_ruby_dln_check_abi() { println!("cargo:rustc-cfg=has_ruby_abi_version"); } let version = Version::current(rbconfig); for v in SUPPORTED_RUBY_VERSIONS.iter() { let v = v.to_owned(); if version < v { println!(r#"cargo:rustc-cfg=ruby_lt_{}_{}"#, v.major(), v.minor()); cfg_capture!(cap, r#"cargo:version_lt_{}_{}=true"#, v.major(), v.minor()); } else { cfg_capture!(cap, r#"cargo:version_lt_{}_{}=false"#, v.major(), v.minor()); } if version <= v { println!(r#"cargo:rustc-cfg=ruby_lte_{}_{}"#, v.major(), v.minor()); cfg_capture!(cap, r#"cargo:version_lte_{}_{}=true"#, v.major(), v.minor()); } else { cfg_capture!( cap, r#"cargo:version_lte_{}_{}=false"#, v.major(), v.minor() ); } if version == v { println!(r#"cargo:rustc-cfg=ruby_eq_{}_{}"#, v.major(), v.minor()); cfg_capture!(cap, r#"cargo:version_eq_{}_{}=true"#, v.major(), v.minor()); } else { cfg_capture!(cap, r#"cargo:version_eq_{}_{}=false"#, v.major(), v.minor()); } if version >= v { println!(r#"cargo:rustc-cfg=ruby_gte_{}_{}"#, v.major(), v.minor()); cfg_capture!(cap, r#"cargo:version_gte_{}_{}=true"#, v.major(), v.minor()); } else { cfg_capture!( cap, r#"cargo:version_gte_{}_{}=false"#, v.major(), v.minor() ); } if version > v { println!(r#"cargo:rustc-cfg=ruby_gt_{}_{}"#, v.major(), v.minor()); cfg_capture!(cap, r#"cargo:version_gt_{}_{}=true"#, v.major(), v.minor()); } else { cfg_capture!(cap, r#"cargo:version_gt_{}_{}=false"#, v.major(), v.minor()); } } cfg_capture!(cap, "cargo:root={}", rbconfig.get("prefix")); cfg_capture!(cap, "cargo:include={}", rbconfig.get("includedir")); cfg_capture!(cap, "cargo:archinclude={}", rbconfig.get("archincludedir")); cfg_capture!(cap, "cargo:version={}", rbconfig.get("ruby_version")); cfg_capture!(cap, "cargo:major={}", rbconfig.get("MAJOR")); cfg_capture!(cap, "cargo:minor={}", rbconfig.get("MINOR")); cfg_capture!(cap, "cargo:teeny={}", rbconfig.get("TEENY")); cfg_capture!(cap, "cargo:patchlevel={}", rbconfig.get("PATCHLEVEL")); for key in rbconfig.all_keys() { cfg_capture!(cap, "cargo:rbconfig_{}={}", key, rbconfig.get(key)); } if is_ruby_static_enabled(rbconfig) { cfg_capture!(cap, "cargo:lib={}", rbconfig.libruby_static_name()); cfg_capture!(cap, "cargo:ruby_static={}", "true"); } else { cfg_capture!(cap, "cargo:lib={}", rbconfig.libruby_so_name()); } cfg_capture!(cap, "cargo:libdir={}", rbconfig.get("libdir")); } fn rustc_cfg(rbconfig: &RbConfig, name: &str, key: &str) { if let Some(k) = rbconfig.get_optional(key) { println!("cargo:rustc-cfg={}=\"{}\"", name, k); } } fn enable_dynamic_lookup(rbconfig: &mut RbConfig) { // See https://github.com/oxidize-rb/rb-sys/issues/88 if cfg!(target_os = "macos") { rbconfig.push_dldflags("-Wl,-undefined,dynamic_lookup"); } } fn expose_cargo_features(cap: &mut File) { for (key, val) in std::env::vars() { if !key.starts_with("CARGO_FEATURE_") { continue; } cfg_capture!(cap, "cargo:{}={}", key.to_lowercase(), val); } } fn warn_deprecated_feature_flags() { if cfg!(feature = "ruby-macros") { println!("cargo:warning=The \"ruby-macros\" feature flag is deprecated and will be removed in a future release. Please use \"stable-api\" instead."); } } rb-sys-0.9.97/build/stable_api_config.rs000064400000000000000000000110241046102023000162440ustar 00000000000000use crate::{ features::is_env_variable_defined, version::{Version, MIN_SUPPORTED_STABLE_VERSION}, }; use std::{convert::TryFrom, error::Error, path::Path}; pub fn setup(current_ruby_version: Version) -> Result<(), Box> { let strategy = Strategy::try_from(current_ruby_version)?; strategy.apply()?; Ok(()) } #[derive(Debug)] enum Strategy { RustOnly(Version), CompiledOnly, RustThenCompiled(Version), Testing(Version), } impl TryFrom for Strategy { type Error = Box; fn try_from(current_ruby_version: Version) -> Result { let mut strategy = None; if current_ruby_version.is_stable() { strategy = Some(Strategy::RustOnly(current_ruby_version)); } else { maybe_warn_old_ruby_version(current_ruby_version); } if is_fallback_enabled() { strategy = Some(Strategy::RustThenCompiled(current_ruby_version)); } if is_testing() { strategy = Some(Strategy::Testing(current_ruby_version)); } if is_force_enabled() { strategy = Some(Strategy::CompiledOnly); } if let Some(strategy) = strategy { return Ok(strategy); } Err("Stable API is needed but could not find a candidate. Try enabling the `stable-api-compiled-fallback` feature in rb-sys.".into()) } } impl Strategy { fn apply(self) -> Result<(), Box> { match self { Strategy::RustOnly(current_ruby_version) => { if current_ruby_version.is_stable() { println!("cargo:rustc-cfg=stable_api_include_rust_impl"); } else { return Err(format!("A stable Ruby API is needed but could not find a candidate. If you are using a stable version of Ruby, try upgrading rb-sys. Otherwise if you are testing against ruby-head or Ruby < {}, enable the `stable-api-compiled-fallback` feature in rb-sys.", MIN_SUPPORTED_STABLE_VERSION).into()); } } Strategy::CompiledOnly => { compile()?; println!("cargo:rustc-cfg=stable_api_enable_compiled_mod"); println!("cargo:rustc-cfg=stable_api_export_compiled_as_api"); } Strategy::RustThenCompiled(current_ruby_version) => { if current_ruby_version.is_stable() { println!("cargo:rustc-cfg=stable_api_has_rust_impl"); println!("cargo:rustc-cfg=stable_api_include_rust_impl"); } else { compile()?; println!("cargo:rustc-cfg=stable_api_enable_compiled_mod"); println!("cargo:rustc-cfg=stable_api_export_compiled_as_api"); } } Strategy::Testing(current_ruby_version) => { compile()?; println!("cargo:rustc-cfg=stable_api_enable_compiled_mod"); if current_ruby_version.is_stable() { println!("cargo:rustc-cfg=stable_api_include_rust_impl"); } else { println!("cargo:rustc-cfg=stable_api_export_compiled_as_api"); } } }; Ok(()) } } fn is_fallback_enabled() -> bool { println!("cargo:rerun-if-env-changed=RB_SYS_STABLE_API_COMPILED_FALLBACK"); is_env_variable_defined("CARGO_FEATURE_STABLE_API_COMPILED_FALLBACK") || cfg!(rb_sys_use_stable_api_compiled_fallback) || is_env_variable_defined("RB_SYS_STABLE_API_COMPILED_FALLBACK") } fn is_force_enabled() -> bool { println!("cargo:rerun-if-env-changed=RB_SYS_STABLE_API_COMPILED_FORCE"); is_env_variable_defined("CARGO_FEATURE_STABLE_API_COMPILED_FORCE") || cfg!(rb_sys_force_stable_api_compiled) || is_env_variable_defined("RB_SYS_STABLE_API_COMPILED_FORCE") } fn is_testing() -> bool { is_env_variable_defined("CARGO_FEATURE_STABLE_API_COMPILED_TESTING") } fn maybe_warn_old_ruby_version(current_ruby_version: Version) { if current_ruby_version < MIN_SUPPORTED_STABLE_VERSION { println!( "cargo:warning=Support for Ruby {} will be removed in a future release.", current_ruby_version ); } } fn compile() -> Result<(), Box> { let mut build = rb_sys_build::cc::Build::new(); let crate_dir = Path::new(env!("CARGO_MANIFEST_DIR")); let path = crate_dir.join("src").join("stable_api").join("compiled.c"); build.file(path); build.try_compile("compiled") } rb-sys-0.9.97/build/version.rs000064400000000000000000000017721046102023000143120ustar 00000000000000use crate::RbConfig; #[allow(dead_code)] pub const LATEST_STABLE_VERSION: Version = Version::new(3, 3); #[allow(dead_code)] pub const MIN_SUPPORTED_STABLE_VERSION: Version = Version::new(2, 6); #[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)] pub struct Version(u32, u32); impl Version { pub const fn new(major: u32, minor: u32) -> Self { Self(major, minor) } pub fn major(&self) -> u32 { self.0 } pub fn minor(&self) -> u32 { self.1 } pub fn current(rbconfig: &RbConfig) -> Version { Self( rbconfig.get("MAJOR").parse::().unwrap() as _, rbconfig.get("MINOR").parse::().unwrap() as _, ) } #[allow(dead_code)] pub fn is_stable(&self) -> bool { *self >= MIN_SUPPORTED_STABLE_VERSION && *self <= LATEST_STABLE_VERSION } } impl std::fmt::Display for Version { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}.{}", self.0, self.1) } } rb-sys-0.9.97/readme.md000064400000000000000000000046321046102023000127350ustar 00000000000000# rb-sys [![Join the discussion](https://img.shields.io/badge/slack-chat-blue.svg)](https://join.slack.com/t/oxidize-rb/shared_invite/zt-16zv5tqte-Vi7WfzxCesdo2TqF_RYBCw) Autogenerated Rust bindings for Ruby. Uses the [`rust-bindgen`](https://github.com/rust-lang/rust-bindgen) crate to generate bindings from the `ruby.h` header.https://github.com/rust-lang/rust-bindgen ## ⚠️ Notice This is a very low-level library. If you are looking to write a gem in Rust, you should probably use https://github.com/matsadler/magnus crate, with the `rb-sys-interop` feature. If you actually _need_ raw/unsafe bindings to libruby, then this crate if for you! ## Usage ### Writing a Ruby gem Ruby gems require a bit of boilerplate to be defined to be usable from Ruby. `rb-sys` makes this process painless by doing the work for you, by simply enabling the `gem` feature. ```toml rb-sys = "0.9" ``` Under the hood this ensures we do not link libruby (unless on Windows), and defines a `ruby_abi_version` function for Ruby 3.2+. [See this example of creating a Ruby gem in Rust](./examples/rust_reverse) ### Embedding libruby in your Rust app _IMPORTANT_: If you are authoring a Ruby gem, you do not need to enable this feature. If you need to link libruby (i.e. you are initializing a Ruby VM in your Rust code), use can enable the `link-ruby` feature: ```toml rb-sys = { version = "0.9", features = ["link-ruby"] } ``` ### Static libruby You can also force static linking of libruby: ```toml rb-sys = { version = "0.9", features = ["ruby-static"] } ``` Alternatively, you can set the `RUBY_STATIC=true` environment variable. ### Other features - `global-allocator`: Report Rust memory allocations to the Ruby GC (_recommended_). - `ruby-static`: Link the static version of libruby. - `link-ruby`: Link libruby. - `bindgen-rbimpls`: Include the Ruby impl types in bindings. - `bindgen-deprecated-types`: Include deprecated Ruby methods in bindings. ## 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. rb-sys-0.9.97/src/bindings.rs000064400000000000000000000010551046102023000141040ustar 00000000000000//! Raw bindings to libruby, generated by bindgen. //! //! This module contains the raw bindings to libruby, generated by bindgen. #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(unknown_lints)] #![allow(deref_nullptr)] #![warn(unknown_lints)] #![allow(clippy::all)] #![allow(rustdoc::broken_intra_doc_links)] #![allow(rustdoc::invalid_rust_codeblocks)] #![allow(rustdoc::invalid_html_tags)] #![allow(deprecated)] include!(env!("RB_SYS_BINDINGS_PATH")); pub use uncategorized::*; pub use unstable::*; rb-sys-0.9.97/src/hidden.rs000064400000000000000000000005541046102023000135450ustar 00000000000000//! Hidden symbols from Ruby that we need to link to, not exposed to users. //! //! Note: Using these symbols is an absolute last resort. Try to use the //! official Ruby C API if at all possible. extern "C" { /// A pointer to the current Ruby VM. #[cfg(all(ruby_gt_2_4, ruby_lte_3_2))] pub(crate) static ruby_current_vm_ptr: *mut crate::ruby_vm_t; } rb-sys-0.9.97/src/lib.rs000064400000000000000000000015231046102023000130550ustar 00000000000000#![allow(rustdoc::bare_urls)] #![doc = include_str!("../readme.md")] pub mod bindings; #[cfg(feature = "stable-api")] pub mod macros; pub mod memory; pub mod special_consts; #[cfg(feature = "stable-api")] pub mod stable_api; pub mod symbol; pub mod tracking_allocator; pub mod value_type; mod hidden; mod ruby_abi_version; mod utils; pub use bindings::*; #[cfg(feature = "stable-api")] pub use macros::*; pub use ruby_abi_version::*; pub use special_consts::*; #[cfg(feature = "stable-api")] pub use stable_api::StableApiDefinition; pub use value_type::*; #[deprecated(since = "0.9.79", note = "Use `VALUE` instead")] pub type Value = VALUE; #[deprecated(since = "0.9.79", note = "Use `VALUE` instead")] pub type RubyValue = VALUE; #[cfg(use_global_allocator)] set_global_tracking_allocator!(); #[cfg(use_ruby_abi_version)] ruby_abi_version!(); rb-sys-0.9.97/src/macros.rs000064400000000000000000000205061046102023000135750ustar 00000000000000//! Implementation of Ruby macros. //! //! Since macros are rely on the C preprocessor, or defined as `inline` C //! functions, they are not available when linking libruby. In order to use the //! libruby macros from Rust, `rb-sys` implements them using the following //! strategies: //! //! 1. For stable versions of Ruby, the macros are implemented as Rust functions //! 2. For ruby-head, the macros are implemented as C functions that are linked //! into the crate. #![allow(rustdoc::broken_intra_doc_links)] #![allow(non_upper_case_globals)] #![allow(non_snake_case)] use crate::ruby_value_type; use crate::stable_api::get_default as api; use crate::StableApiDefinition; use crate::VALUE; use std::os::raw::{c_char, c_long}; /// Emulates Ruby's "if" statement. /// /// - @param[in] obj An arbitrary ruby object. /// - @retval false `obj` is either ::RUBY_Qfalse or ::RUBY_Qnil. /// - @retval true Anything else. /// /// ``` /// use rb_sys::special_consts::*; /// /// assert!(!TEST(Qfalse)); /// assert!(!TEST(Qnil)); /// assert!(TEST(Qtrue)); /// ``` #[inline] pub fn TEST>(obj: T) -> bool { api().rb_test(obj.into()) } /// Checks if the given object is nil. /// /// - @param[in] obj An arbitrary ruby object. /// - @retval true `obj` is ::RUBY_Qnil. /// - @retval false Anything else. /// /// ### Example /// /// ``` /// use rb_sys::special_consts::*; /// /// assert!(NIL_P(Qnil)); /// assert!(!NIL_P(Qtrue)); /// ``` #[inline] pub fn NIL_P>(obj: T) -> bool { api().nil_p(obj.into()) } /// Checks if the given object is a so-called Fixnum. /// /// - @param[in] obj An arbitrary ruby object. /// - @retval true `obj` is a Fixnum. /// - @retval false Anything else. /// - @note Fixnum was a thing in the 20th century, but it is rather an /// implementation detail today. #[inline] pub fn FIXNUM_P>(obj: T) -> bool { api().fixnum_p(obj.into()) } /// Checks if the given object is a static symbol. /// /// - @param[in] obj An arbitrary ruby object. /// - @retval true `obj` is a static symbol /// - @retval false Anything else. /// - @see RB_DYNAMIC_SYM_P() /// - @see RB_SYMBOL_P() /// - @note These days there are static and dynamic symbols, just like we /// once had Fixnum/Bignum back in the old days. #[inline] pub fn STATIC_SYM_P>(obj: T) -> bool { api().static_sym_p(obj.into()) } /// Get the backend storage of a Ruby array. /// /// ### Safety /// /// This function is unsafe because it dereferences a raw pointer and returns /// raw pointers to Ruby memory. The caller must ensure that the pointer stays live /// for the duration of usage the the underlying array (by either GC marking or /// keeping the RArray on the stack). /// /// - @param[in] a An object of ::RArray. /// - @return Its backend storage. #[inline] pub unsafe fn RARRAY_CONST_PTR>(obj: T) -> *const VALUE { api().rarray_const_ptr(obj.into()) } /// Get the length of a Ruby array. /// /// ### Safety /// /// This function is unsafe because it dereferences a raw pointer in order to /// access internal Ruby memory. /// /// - @param[in] a An object of ::RArray. /// - @return Its length. #[inline] pub unsafe fn RARRAY_LEN>(obj: T) -> c_long { api().rarray_len(obj.into()) } /// Get the length of a Ruby string. /// /// ### Safety /// /// This function is unsafe because it dereferences a raw pointer in order to /// access internal Ruby memory. /// /// - @param[in] a An object of ::RString. /// - @return Its length. #[inline] pub unsafe fn RSTRING_LEN>(obj: T) -> c_long { api().rstring_len(obj.into()) } /// Get the backend storage of a Ruby string. /// /// ### Safety /// /// This function is unsafe because it dereferences a raw pointer and returns /// raw pointers to Ruby memory. /// /// - @param[in] a An object of ::RString. /// - @return Its backend storage #[inline] pub unsafe fn RSTRING_PTR>(obj: T) -> *const c_char { api().rstring_ptr(obj.into()) } /// Checks if the given object is a so-called Flonum. /// /// @param[in] obj An arbitrary ruby object. /// @retval true `obj` is a Flonum. /// @retval false Anything else. /// @see RB_FLOAT_TYPE_P() /// @note These days there are Flonums and non-Flonum floats, just like we /// once had Fixnum/Bignum back in the old days. #[inline] pub fn FLONUM_P>(#[allow(unused)] obj: T) -> bool { api().flonum_p(obj.into()) } /// Checks if the given object is an immediate i.e. an object which has no /// corresponding storage inside of the object space. /// /// @param[in] obj An arbitrary ruby object. /// @retval true `obj` is a Flonum. /// @retval false Anything else. /// @see RB_FLOAT_TYPE_P() /// @note The concept of "immediate" is purely C specific. #[inline] pub fn IMMEDIATE_P>(obj: T) -> bool { api().immediate_p(obj.into()) } /// Checks if the given object is of enum ::ruby_special_consts. /// /// @param[in] obj An arbitrary ruby object. /// @retval true `obj` is a special constant. /// @retval false Anything else. /// /// ### Example /// /// ``` /// use rb_sys::special_consts::*; /// /// assert!(SPECIAL_CONST_P(Qnil)); /// assert!(SPECIAL_CONST_P(Qtrue)); /// assert!(SPECIAL_CONST_P(Qfalse)); /// ``` #[inline] pub fn SPECIAL_CONST_P>(obj: T) -> bool { api().special_const_p(obj.into()) } /// Queries the type of the object. /// /// @param[in] obj Object in question. /// @pre `obj` must not be a special constant. /// @return The type of `obj`. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. #[inline] pub unsafe fn RB_BUILTIN_TYPE(obj: VALUE) -> ruby_value_type { api().builtin_type(obj) } /// Queries if the object is an instance of ::rb_cInteger. /// /// @param[in] obj Object in question. /// @retval true It is. /// @retval false It isn't. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. #[inline] pub unsafe fn RB_INTEGER_TYPE_P(obj: VALUE) -> bool { api().integer_type_p(obj) } /// Queries if the object is a dynamic symbol. /// /// @param[in] obj Object in question. /// @retval true It is. /// @retval false It isn't. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. #[inline] pub unsafe fn RB_DYNAMIC_SYM_P(obj: VALUE) -> bool { api().dynamic_sym_p(obj) } /// Queries if the object is an instance of ::rb_cSymbol. /// /// @param[in] obj Object in question. /// @retval true It is. /// @retval false It isn't. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. #[inline] pub unsafe fn RB_SYMBOL_P(obj: VALUE) -> bool { api().symbol_p(obj) } /// Identical to RB_BUILTIN_TYPE(), except it can also accept special constants. /// /// @param[in] obj Object in question. /// @return The type of `obj`. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. #[inline] pub unsafe fn RB_TYPE(value: VALUE) -> ruby_value_type { api().rb_type(value) } /// Queries if the given object is of given type. /// /// @param[in] obj An object. /// @param[in] t A type. /// @retval true `obj` is of type `t`. /// @retval false Otherwise. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. #[inline] pub unsafe fn RB_TYPE_P(obj: VALUE, ty: ruby_value_type) -> bool { api().type_p(obj, ty) } /// Queries if the object is an instance of ::rb_cFloat. /// /// @param[in] obj Object in question. /// @retval true It is. /// @retval false It isn't. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. #[inline] pub unsafe fn RB_FLOAT_TYPE_P(obj: VALUE) -> bool { api().float_type_p(obj) } rb-sys-0.9.97/src/memory.rs000064400000000000000000000040641046102023000136220ustar 00000000000000/// Prevents premature destruction of local objects. /// /// Ruby's garbage collector is conservative; it scans the C level machine stack as well. /// Possible in-use Ruby objects must remain visible on stack, to be properly marked as such. /// However, Rust's compiler optimizations might remove the references to these objects from /// the stack when they are not being used directly. /// /// Consider the following example: /// /// ```ignore /// use rb_sys::{rb_str_new_cstr, rb_str_cat_cstr, RSTRING_PTR, rb_gc_guard}; /// /// unsafe { /// let s = rb_str_new_cstr(" world\0".as_ptr() as _); /// let sptr = RSTRING_PTR(s); /// let t = rb_str_new_cstr("hello,\0".as_ptr() as _); // Possible GC invocation /// let u = rb_str_cat_cstr(t, sptr); /// rb_gc_guard!(s); // ensure `s` (and thus `sptr`) do not get GC-ed /// } /// ``` /// /// In this example, without the `rb_gc_guard!`, the last use of `s` is before the last use /// of `sptr`. Compilers could think `s` and `t` are allowed to overlap. That would /// eliminate `s` from the stack, while `sptr` is still in use. If our GC runs at that /// very moment, `s` gets swept out, which also destroys `sptr`. /// /// In order to prevent this scenario, `rb_gc_guard!` must be placed after the last use /// of `sptr`. Placing `rb_gc_guard!` before dereferencing `sptr` would be of no use. /// /// Using the `rb_gc_guard!` macro has the following advantages: /// /// - the intent of the macro use is clear. /// /// - `rb_gc_guard!` only affects its call site, without negatively affecting other systems. /// /// # Example /// ```no_run /// use rb_sys::{rb_utf8_str_new_cstr, rb_gc_guard}; /// /// let my_string = unsafe { rb_utf8_str_new_cstr("hello world\0".as_ptr() as _) }; /// let _ = rb_gc_guard!(my_string); /// ``` #[macro_export] macro_rules! rb_gc_guard { ($v:expr) => {{ unsafe { let val: $crate::VALUE = $v; let rb_gc_guarded_ptr = std::ptr::read_volatile(&&val); std::arch::asm!("/* {0} */", in(reg) rb_gc_guarded_ptr); *rb_gc_guarded_ptr } }}; } rb-sys-0.9.97/src/ruby_abi_version.rs000064400000000000000000000016351046102023000156540ustar 00000000000000//! Helper to define the `ruby_abi_version` function needed for extensions. //! //! Since Ruby 3.2, gems are required to define a `ruby_abi_version` function. //! For C extensions, this is done transparently by including `ruby.h`, but for //! Rust we have to define it ourselves. This is enabled automatically by when //! compiling a gem. #[doc(hidden)] #[cfg(not(has_ruby_abi_version))] pub const __RB_SYS_RUBY_ABI_VERSION: std::os::raw::c_ulonglong = 0; #[doc(hidden)] #[cfg(has_ruby_abi_version)] pub const __RB_SYS_RUBY_ABI_VERSION: std::os::raw::c_ulonglong = crate::RUBY_ABI_VERSION as _; #[macro_export] macro_rules! ruby_abi_version { () => { /// Defines the `ruby_abi_version` function needed for Ruby extensions. #[no_mangle] #[allow(unused)] pub extern "C" fn ruby_abi_version() -> std::os::raw::c_ulonglong { $crate::__RB_SYS_RUBY_ABI_VERSION } }; } rb-sys-0.9.97/src/special_consts.rs000064400000000000000000000022121046102023000153140ustar 00000000000000#![allow(rustdoc::broken_intra_doc_links)] #![allow(non_upper_case_globals)] #![allow(non_snake_case)] //! Definitions for Ruby's special constants. //! //! Makes it easier to reference important Ruby constants, without having to dig //! around in bindgen's output. use crate::{ruby_special_consts, VALUE}; pub const Qfalse: ruby_special_consts = ruby_special_consts::RUBY_Qfalse; pub const Qtrue: ruby_special_consts = ruby_special_consts::RUBY_Qtrue; pub const Qnil: ruby_special_consts = ruby_special_consts::RUBY_Qnil; pub const Qundef: ruby_special_consts = ruby_special_consts::RUBY_Qundef; pub const IMMEDIATE_MASK: ruby_special_consts = ruby_special_consts::RUBY_IMMEDIATE_MASK; pub const FIXNUM_FLAG: ruby_special_consts = ruby_special_consts::RUBY_FIXNUM_FLAG; pub const FLONUM_MASK: ruby_special_consts = ruby_special_consts::RUBY_FLONUM_MASK; pub const FLONUM_FLAG: ruby_special_consts = ruby_special_consts::RUBY_FLONUM_FLAG; pub const SYMBOL_FLAG: ruby_special_consts = ruby_special_consts::RUBY_SYMBOL_FLAG; #[allow(clippy::from_over_into)] impl Into for ruby_special_consts { fn into(self) -> VALUE { self as VALUE } } rb-sys-0.9.97/src/stable_api/compiled.c000064400000000000000000000023361046102023000160070ustar 00000000000000#include "ruby.h" long impl_rstring_len(VALUE obj) { return RSTRING_LEN(obj); } char * impl_rstring_ptr(VALUE obj) { return RSTRING_PTR(obj); } long impl_rarray_len(VALUE obj) { return RARRAY_LEN(obj); } const VALUE * impl_rarray_const_ptr(VALUE obj) { return RARRAY_CONST_PTR(obj); } int impl_special_const_p(VALUE obj) { return SPECIAL_CONST_P(obj); } enum ruby_value_type impl_builtin_type(VALUE obj) { return RB_BUILTIN_TYPE(obj); } int impl_nil_p(VALUE obj) { return NIL_P(obj); } int impl_fixnum_p(VALUE obj) { return FIXNUM_P(obj); } int impl_static_sym_p(VALUE obj) { return STATIC_SYM_P(obj); } int impl_flonum_p(VALUE obj) { return FLONUM_P(obj); } int impl_immediate_p(VALUE obj) { return IMMEDIATE_P(obj); } int impl_rb_test(VALUE obj) { return RB_TEST(obj); } int impl_type_p(VALUE obj, enum ruby_value_type type) { return RB_TYPE_P(obj, type); } int impl_dynamic_sym_p(VALUE obj) { return RB_DYNAMIC_SYM_P(obj); } int impl_symbol_p(VALUE obj) { return RB_SYMBOL_P(obj); } int impl_float_type_p(VALUE obj) { return RB_FLOAT_TYPE_P(obj); } enum ruby_value_type impl_rb_type(VALUE obj) { return rb_type(obj); } int impl_integer_type_p(VALUE obj) { return RB_INTEGER_TYPE_P(obj); } rb-sys-0.9.97/src/stable_api/compiled.rs000064400000000000000000000073231046102023000162120ustar 00000000000000use super::StableApiDefinition; use crate::{ruby_value_type, VALUE}; use std::os::raw::{c_char, c_long}; #[allow(dead_code)] extern "C" { #[link_name = "impl_rstring_len"] fn impl_rstring_len(str: VALUE) -> c_long; #[link_name = "impl_rstring_ptr"] fn impl_rstring_ptr(str: VALUE) -> *const c_char; #[link_name = "impl_rarray_len"] fn impl_rarray_len(ary: VALUE) -> c_long; #[link_name = "impl_rarray_const_ptr"] fn impl_rarray_const_ptr(ary: VALUE) -> *const VALUE; #[link_name = "impl_special_const_p"] fn impl_special_const_p(value: VALUE) -> bool; #[link_name = "impl_builtin_type"] fn impl_builtin_type(obj: VALUE) -> ruby_value_type; #[link_name = "impl_nil_p"] fn impl_nil_p(obj: VALUE) -> bool; #[link_name = "impl_fixnum_p"] fn impl_fixnum_p(obj: VALUE) -> bool; #[link_name = "impl_static_sym_p"] fn impl_static_sym_p(obj: VALUE) -> bool; #[link_name = "impl_flonum_p"] fn impl_flonum_p(obj: VALUE) -> bool; #[link_name = "impl_immediate_p"] fn impl_immediate_p(obj: VALUE) -> bool; #[link_name = "impl_rb_test"] fn impl_rb_test(obj: VALUE) -> bool; #[link_name = "impl_type_p"] fn impl_type_p(obj: VALUE, ty: ruby_value_type) -> bool; #[link_name = "impl_dynamic_sym_p"] fn impl_dynamic_sym_p(obj: VALUE) -> bool; #[link_name = "impl_symbol_p"] fn impl_symbol_p(obj: VALUE) -> bool; #[link_name = "impl_float_type_p"] fn impl_float_type_p(obj: VALUE) -> bool; #[link_name = "impl_rb_type"] fn impl_rb_type(obj: VALUE) -> ruby_value_type; #[link_name = "impl_integer_type_p"] fn impl_integer_type_p(obj: VALUE) -> bool; } pub struct Definition; impl StableApiDefinition for Definition { #[inline] unsafe fn rstring_len(&self, obj: VALUE) -> std::os::raw::c_long { impl_rstring_len(obj) } #[inline] unsafe fn rstring_ptr(&self, obj: VALUE) -> *const std::os::raw::c_char { impl_rstring_ptr(obj) } #[inline] unsafe fn rarray_len(&self, obj: VALUE) -> std::os::raw::c_long { impl_rarray_len(obj) } #[inline] unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE { impl_rarray_const_ptr(obj) } #[inline] fn special_const_p(&self, value: VALUE) -> bool { unsafe { impl_special_const_p(value) } } #[inline] unsafe fn builtin_type(&self, obj: VALUE) -> ruby_value_type { impl_builtin_type(obj) } #[inline] fn nil_p(&self, obj: VALUE) -> bool { unsafe { impl_nil_p(obj) } } #[inline] fn fixnum_p(&self, obj: VALUE) -> bool { unsafe { impl_fixnum_p(obj) } } #[inline] fn static_sym_p(&self, obj: VALUE) -> bool { unsafe { impl_static_sym_p(obj) } } #[inline] fn flonum_p(&self, obj: VALUE) -> bool { unsafe { impl_flonum_p(obj) } } #[inline] fn immediate_p(&self, obj: VALUE) -> bool { unsafe { impl_immediate_p(obj) } } #[inline] fn rb_test(&self, obj: VALUE) -> bool { unsafe { impl_rb_test(obj) } } #[inline] unsafe fn type_p(&self, obj: VALUE, ty: ruby_value_type) -> bool { impl_type_p(obj, ty) } #[inline] unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool { impl_dynamic_sym_p(obj) } #[inline] unsafe fn symbol_p(&self, obj: VALUE) -> bool { impl_symbol_p(obj) } #[inline] unsafe fn float_type_p(&self, obj: VALUE) -> bool { impl_float_type_p(obj) } #[inline] unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type { impl_rb_type(obj) } #[inline] unsafe fn integer_type_p(&self, obj: VALUE) -> bool { impl_integer_type_p(obj) } } rb-sys-0.9.97/src/stable_api/ruby_2_6.rs000064400000000000000000000146131046102023000160450ustar 00000000000000use super::StableApiDefinition; use crate::ruby_rarray_flags::*; use crate::ruby_rstring_flags::*; use crate::{ internal::{RArray, RString}, value_type, VALUE, }; use std::os::raw::{c_char, c_long}; #[cfg(not(ruby_eq_2_6))] compile_error!("This file should only be included in Ruby 2.6 builds"); pub struct Definition; impl StableApiDefinition for Definition { #[inline] unsafe fn rstring_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & RSTRING_NOEMBED as VALUE) != 0; if !is_heap { let mut f = rstring.basic.flags; f &= RSTRING_EMBED_LEN_MASK as VALUE; f >>= RSTRING_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rstring.as_.heap.len } } #[inline] unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & RSTRING_NOEMBED as VALUE) != 0; let ptr = if !is_heap { std::ptr::addr_of!(rstring.as_.ary) as *const _ } else { rstring.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] unsafe fn rarray_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & RARRAY_EMBED_FLAG as VALUE) != 0; if is_embedded { let mut f = rarray.basic.flags; f &= RARRAY_EMBED_LEN_MASK as VALUE; f >>= RARRAY_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rarray.as_.heap.len } } #[inline] unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & RARRAY_EMBED_FLAG as VALUE) != 0; let ptr = if is_embedded { rarray.as_.ary.as_ptr() } else { rarray.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] fn special_const_p(&self, value: VALUE) -> bool { let is_immediate = value & (crate::special_consts::IMMEDIATE_MASK as VALUE) != 0; let test = (value & !(crate::Qnil as VALUE)) != 0; is_immediate || !test } #[inline] unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type { let rbasic = obj as *const crate::RBasic; let ret: u32 = ((*rbasic).flags & crate::ruby_value_type::RUBY_T_MASK as VALUE) as _; std::mem::transmute::<_, crate::ruby_value_type>(ret) } #[inline] fn nil_p(&self, obj: VALUE) -> bool { obj == (crate::Qnil as VALUE) } #[inline] fn fixnum_p(&self, obj: VALUE) -> bool { (obj & crate::FIXNUM_FLAG as VALUE) != 0 } #[inline] fn static_sym_p(&self, obj: VALUE) -> bool { let mask = !(VALUE::MAX << crate::ruby_special_consts::RUBY_SPECIAL_SHIFT as VALUE); (obj & mask) == crate::ruby_special_consts::RUBY_SYMBOL_FLAG as VALUE } #[inline] fn flonum_p(&self, obj: VALUE) -> bool { #[cfg(ruby_use_flonum = "true")] let ret = (obj & crate::FLONUM_MASK as VALUE) == crate::FLONUM_FLAG as VALUE; #[cfg(not(ruby_use_flonum = "true"))] let ret = false; ret } #[inline] fn immediate_p(&self, obj: VALUE) -> bool { (obj & crate::special_consts::IMMEDIATE_MASK as VALUE) != 0 } #[inline] fn rb_test(&self, obj: VALUE) -> bool { (obj & !(crate::Qnil as VALUE)) != 0 } #[inline] unsafe fn type_p(&self, obj: VALUE, t: crate::ruby_value_type) -> bool { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if t == RUBY_T_TRUE { obj == RUBY_Qtrue as _ } else if t == RUBY_T_FALSE { obj == RUBY_Qfalse as _ } else if t == RUBY_T_NIL { obj == RUBY_Qnil as _ } else if t == RUBY_T_UNDEF { obj == RUBY_Qundef as _ } else if t == RUBY_T_FIXNUM { self.fixnum_p(obj) } else if t == RUBY_T_SYMBOL { self.symbol_p(obj) } else if t == RUBY_T_FLOAT { self.float_type_p(obj) } else if self.special_const_p(obj) { false } else if t == self.builtin_type(obj) { true } else { t == self.rb_type(obj) } } unsafe fn symbol_p(&self, obj: VALUE) -> bool { self.static_sym_p(obj) || self.dynamic_sym_p(obj) } unsafe fn float_type_p(&self, obj: VALUE) -> bool { if self.flonum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_FLOAT } } unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if !self.special_const_p(obj) { self.builtin_type(obj) } else if obj == RUBY_Qfalse as _ { RUBY_T_FALSE } else if obj == RUBY_Qnil as _ { RUBY_T_NIL } else if obj == RUBY_Qtrue as _ { RUBY_T_TRUE } else if obj == RUBY_Qundef as _ { RUBY_T_UNDEF } else if self.fixnum_p(obj) { RUBY_T_FIXNUM } else if self.static_sym_p(obj) { RUBY_T_SYMBOL } else { debug_assert!(self.flonum_p(obj)); RUBY_T_FLOAT } } unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool { if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_SYMBOL } } #[inline] unsafe fn integer_type_p(&self, obj: VALUE) -> bool { if self.fixnum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_BIGNUM } } } rb-sys-0.9.97/src/stable_api/ruby_2_7.rs000064400000000000000000000151351046102023000160460ustar 00000000000000use super::StableApiDefinition; use crate::{ internal::{RArray, RString}, value_type, VALUE, }; use std::os::raw::{c_char, c_long}; #[cfg(not(ruby_eq_2_7))] compile_error!("This file should only be included in Ruby 2.7 builds"); pub struct Definition; impl StableApiDefinition for Definition { #[inline] unsafe fn rstring_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; if !is_heap { use crate::ruby_rstring_flags::RSTRING_EMBED_LEN_SHIFT; let mut f = rstring.basic.flags; f &= crate::ruby_rstring_flags::RSTRING_EMBED_LEN_MASK as VALUE; f >>= RSTRING_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rstring.as_.heap.len } } #[inline] unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; let ptr = if !is_heap { std::ptr::addr_of!(rstring.as_.ary) as *const _ } else { rstring.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] unsafe fn rarray_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; if is_embedded { let mut f = rarray.basic.flags; f &= crate::ruby_rarray_flags::RARRAY_EMBED_LEN_MASK as VALUE; f >>= crate::ruby_rarray_flags::RARRAY_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rarray.as_.heap.len } } #[inline] unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; let ptr = if is_embedded { std::ptr::addr_of!(rarray.as_.ary) as *const _ } else { rarray.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] fn special_const_p(&self, value: VALUE) -> bool { let is_immediate = value & (crate::special_consts::IMMEDIATE_MASK as VALUE) != 0; let test = (value & !(crate::Qnil as VALUE)) != 0; is_immediate || !test } #[inline] unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type { let rbasic = obj as *const crate::RBasic; let ret: u32 = ((*rbasic).flags & crate::ruby_value_type::RUBY_T_MASK as VALUE) as _; std::mem::transmute::<_, crate::ruby_value_type>(ret) } #[inline] fn nil_p(&self, obj: VALUE) -> bool { obj == (crate::Qnil as VALUE) } #[inline] fn fixnum_p(&self, obj: VALUE) -> bool { (obj & crate::FIXNUM_FLAG as VALUE) != 0 } #[inline] fn static_sym_p(&self, obj: VALUE) -> bool { let mask = !(VALUE::MAX << crate::ruby_special_consts::RUBY_SPECIAL_SHIFT as VALUE); (obj & mask) == crate::ruby_special_consts::RUBY_SYMBOL_FLAG as VALUE } #[inline] fn flonum_p(&self, obj: VALUE) -> bool { #[cfg(ruby_use_flonum = "true")] let ret = (obj & crate::FLONUM_MASK as VALUE) == crate::FLONUM_FLAG as VALUE; #[cfg(not(ruby_use_flonum = "true"))] let ret = false; ret } #[inline] fn immediate_p(&self, obj: VALUE) -> bool { (obj & crate::special_consts::IMMEDIATE_MASK as VALUE) != 0 } #[inline] fn rb_test(&self, obj: VALUE) -> bool { (obj & !(crate::Qnil as VALUE)) != 0 } #[inline] unsafe fn type_p(&self, obj: VALUE, t: crate::ruby_value_type) -> bool { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if t == RUBY_T_TRUE { obj == RUBY_Qtrue as _ } else if t == RUBY_T_FALSE { obj == RUBY_Qfalse as _ } else if t == RUBY_T_NIL { obj == RUBY_Qnil as _ } else if t == RUBY_T_UNDEF { obj == RUBY_Qundef as _ } else if t == RUBY_T_FIXNUM { self.fixnum_p(obj) } else if t == RUBY_T_SYMBOL { self.symbol_p(obj) } else if t == RUBY_T_FLOAT { self.float_type_p(obj) } else if self.special_const_p(obj) { false } else if t == self.builtin_type(obj) { true } else { t == self.rb_type(obj) } } unsafe fn symbol_p(&self, obj: VALUE) -> bool { self.static_sym_p(obj) || self.dynamic_sym_p(obj) } unsafe fn float_type_p(&self, obj: VALUE) -> bool { if self.flonum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_FLOAT } } unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if !self.special_const_p(obj) { self.builtin_type(obj) } else if obj == RUBY_Qfalse as _ { RUBY_T_FALSE } else if obj == RUBY_Qnil as _ { RUBY_T_NIL } else if obj == RUBY_Qtrue as _ { RUBY_T_TRUE } else if obj == RUBY_Qundef as _ { RUBY_T_UNDEF } else if self.fixnum_p(obj) { RUBY_T_FIXNUM } else if self.static_sym_p(obj) { RUBY_T_SYMBOL } else { debug_assert!(self.flonum_p(obj)); RUBY_T_FLOAT } } unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool { if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_SYMBOL } } #[inline] unsafe fn integer_type_p(&self, obj: VALUE) -> bool { if self.fixnum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_BIGNUM } } } rb-sys-0.9.97/src/stable_api/ruby_3_0.rs000064400000000000000000000156071046102023000160440ustar 00000000000000use super::StableApiDefinition; use crate::{ internal::{RArray, RString}, value_type, VALUE, }; use std::os::raw::{c_char, c_long}; #[cfg(not(ruby_eq_3_0))] compile_error!("This file should only be included in Ruby 3.0 builds"); pub struct Definition; impl StableApiDefinition for Definition { #[inline] unsafe fn rstring_len(&self, obj: VALUE) -> c_long { unsafe { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; if !is_heap { use crate::ruby_rstring_consts::RSTRING_EMBED_LEN_SHIFT; let mut f = rstring.basic.flags; f &= crate::ruby_rstring_flags::RSTRING_EMBED_LEN_MASK as VALUE; f >>= RSTRING_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rstring.as_.heap.len } } } #[inline] unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char { unsafe { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; let ptr = if !is_heap { std::ptr::addr_of!(rstring.as_.ary) as *const _ } else { rstring.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } } #[inline] unsafe fn rarray_len(&self, obj: VALUE) -> c_long { unsafe { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; if is_embedded { let mut f = rarray.basic.flags; f &= crate::ruby_rarray_flags::RARRAY_EMBED_LEN_MASK as VALUE; f >>= crate::ruby_rarray_consts::RARRAY_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rarray.as_.heap.len } } } #[inline] unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE { unsafe { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; let ptr = if is_embedded { std::ptr::addr_of!(rarray.as_.ary) as *const _ } else { rarray.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } } #[inline] fn special_const_p(&self, value: VALUE) -> bool { let is_immediate = value & (crate::special_consts::IMMEDIATE_MASK as VALUE) != 0; let test = (value & !(crate::Qnil as VALUE)) != 0; is_immediate || !test } #[inline] unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type { let rbasic = obj as *const crate::RBasic; let ret: u32 = ((*rbasic).flags & crate::ruby_value_type::RUBY_T_MASK as VALUE) as _; std::mem::transmute::<_, crate::ruby_value_type>(ret) } #[inline] fn nil_p(&self, obj: VALUE) -> bool { obj == (crate::Qnil as VALUE) } #[inline] fn fixnum_p(&self, obj: VALUE) -> bool { (obj & crate::FIXNUM_FLAG as VALUE) != 0 } #[inline] fn static_sym_p(&self, obj: VALUE) -> bool { let mask = !(VALUE::MAX << crate::ruby_special_consts::RUBY_SPECIAL_SHIFT as VALUE); (obj & mask) == crate::ruby_special_consts::RUBY_SYMBOL_FLAG as VALUE } #[inline] fn flonum_p(&self, obj: VALUE) -> bool { #[cfg(ruby_use_flonum = "true")] let ret = (obj & crate::FLONUM_MASK as VALUE) == crate::FLONUM_FLAG as VALUE; #[cfg(not(ruby_use_flonum = "true"))] let ret = false; ret } #[inline] fn immediate_p(&self, obj: VALUE) -> bool { (obj & crate::special_consts::IMMEDIATE_MASK as VALUE) != 0 } #[inline] fn rb_test(&self, obj: VALUE) -> bool { (obj & !(crate::Qnil as VALUE)) != 0 } #[inline] unsafe fn type_p(&self, obj: VALUE, t: crate::ruby_value_type) -> bool { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if t == RUBY_T_TRUE { obj == RUBY_Qtrue as _ } else if t == RUBY_T_FALSE { obj == RUBY_Qfalse as _ } else if t == RUBY_T_NIL { obj == RUBY_Qnil as _ } else if t == RUBY_T_UNDEF { obj == RUBY_Qundef as _ } else if t == RUBY_T_FIXNUM { self.fixnum_p(obj) } else if t == RUBY_T_SYMBOL { self.symbol_p(obj) } else if t == RUBY_T_FLOAT { self.float_type_p(obj) } else if self.special_const_p(obj) { false } else if t == self.builtin_type(obj) { true } else { t == self.rb_type(obj) } } unsafe fn symbol_p(&self, obj: VALUE) -> bool { self.static_sym_p(obj) || self.dynamic_sym_p(obj) } unsafe fn float_type_p(&self, obj: VALUE) -> bool { if self.flonum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_FLOAT } } unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if !self.special_const_p(obj) { self.builtin_type(obj) } else if obj == RUBY_Qfalse as _ { RUBY_T_FALSE } else if obj == RUBY_Qnil as _ { RUBY_T_NIL } else if obj == RUBY_Qtrue as _ { RUBY_T_TRUE } else if obj == RUBY_Qundef as _ { RUBY_T_UNDEF } else if self.fixnum_p(obj) { RUBY_T_FIXNUM } else if self.static_sym_p(obj) { RUBY_T_SYMBOL } else { debug_assert!(self.flonum_p(obj)); RUBY_T_FLOAT } } unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool { if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_SYMBOL } } #[inline] unsafe fn integer_type_p(&self, obj: VALUE) -> bool { if self.fixnum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_BIGNUM } } } rb-sys-0.9.97/src/stable_api/ruby_3_1.rs000064400000000000000000000151461046102023000160430ustar 00000000000000use super::StableApiDefinition; use crate::{ internal::{RArray, RString}, value_type, VALUE, }; use std::os::raw::{c_char, c_long}; #[cfg(not(ruby_eq_3_1))] compile_error!("This file should only be included in Ruby 3.1 builds"); pub struct Definition; impl StableApiDefinition for Definition { #[inline] unsafe fn rstring_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; if !is_heap { use crate::ruby_rstring_consts::RSTRING_EMBED_LEN_SHIFT; let mut f = rstring.basic.flags; f &= crate::ruby_rstring_flags::RSTRING_EMBED_LEN_MASK as VALUE; f >>= RSTRING_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rstring.as_.heap.len } } #[inline] unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; let ptr = if !is_heap { std::ptr::addr_of!(rstring.as_.embed.ary) as *const _ } else { rstring.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] unsafe fn rarray_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; if is_embedded { let mut f = rarray.basic.flags; f &= crate::ruby_rarray_flags::RARRAY_EMBED_LEN_MASK as VALUE; f >>= crate::ruby_rarray_consts::RARRAY_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rarray.as_.heap.len } } #[inline] unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; let ret = if is_embedded { std::ptr::addr_of!(rarray.as_.ary) as *const _ } else { rarray.as_.heap.ptr }; assert!(!ret.is_null()); ret } #[inline] fn special_const_p(&self, value: VALUE) -> bool { let is_immediate = value & (crate::special_consts::IMMEDIATE_MASK as VALUE) != 0; let test = (value & !(crate::Qnil as VALUE)) != 0; is_immediate || !test } #[inline] unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type { let rbasic = obj as *const crate::RBasic; let ret: u32 = ((*rbasic).flags & crate::ruby_value_type::RUBY_T_MASK as VALUE) as _; std::mem::transmute::<_, crate::ruby_value_type>(ret) } #[inline] fn nil_p(&self, obj: VALUE) -> bool { obj == (crate::Qnil as VALUE) } #[inline] fn fixnum_p(&self, obj: VALUE) -> bool { (obj & crate::FIXNUM_FLAG as VALUE) != 0 } #[inline] fn static_sym_p(&self, obj: VALUE) -> bool { let mask = !(VALUE::MAX << crate::ruby_special_consts::RUBY_SPECIAL_SHIFT as VALUE); (obj & mask) == crate::ruby_special_consts::RUBY_SYMBOL_FLAG as VALUE } #[inline] fn flonum_p(&self, obj: VALUE) -> bool { #[cfg(ruby_use_flonum = "true")] let ret = (obj & crate::FLONUM_MASK as VALUE) == crate::FLONUM_FLAG as VALUE; #[cfg(not(ruby_use_flonum = "true"))] let ret = false; ret } #[inline] fn immediate_p(&self, obj: VALUE) -> bool { (obj & crate::special_consts::IMMEDIATE_MASK as VALUE) != 0 } #[inline] fn rb_test(&self, obj: VALUE) -> bool { (obj & !(crate::Qnil as VALUE)) != 0 } #[inline] unsafe fn type_p(&self, obj: VALUE, t: crate::ruby_value_type) -> bool { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if t == RUBY_T_TRUE { obj == RUBY_Qtrue as _ } else if t == RUBY_T_FALSE { obj == RUBY_Qfalse as _ } else if t == RUBY_T_NIL { obj == RUBY_Qnil as _ } else if t == RUBY_T_UNDEF { obj == RUBY_Qundef as _ } else if t == RUBY_T_FIXNUM { self.fixnum_p(obj) } else if t == RUBY_T_SYMBOL { self.symbol_p(obj) } else if t == RUBY_T_FLOAT { self.float_type_p(obj) } else if self.special_const_p(obj) { false } else if t == self.builtin_type(obj) { true } else { t == self.rb_type(obj) } } unsafe fn symbol_p(&self, obj: VALUE) -> bool { self.static_sym_p(obj) || self.dynamic_sym_p(obj) } unsafe fn float_type_p(&self, obj: VALUE) -> bool { if self.flonum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_FLOAT } } unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if !self.special_const_p(obj) { self.builtin_type(obj) } else if obj == RUBY_Qfalse as _ { RUBY_T_FALSE } else if obj == RUBY_Qnil as _ { RUBY_T_NIL } else if obj == RUBY_Qtrue as _ { RUBY_T_TRUE } else if obj == RUBY_Qundef as _ { RUBY_T_UNDEF } else if self.fixnum_p(obj) { RUBY_T_FIXNUM } else if self.static_sym_p(obj) { RUBY_T_SYMBOL } else { debug_assert!(self.flonum_p(obj)); RUBY_T_FLOAT } } unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool { if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_SYMBOL } } #[inline] unsafe fn integer_type_p(&self, obj: VALUE) -> bool { if self.fixnum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_BIGNUM } } } rb-sys-0.9.97/src/stable_api/ruby_3_2.rs000064400000000000000000000146721046102023000160470ustar 00000000000000use super::StableApiDefinition; use crate::{ internal::{RArray, RString}, value_type, VALUE, }; use std::os::raw::{c_char, c_long}; #[cfg(not(ruby_eq_3_2))] compile_error!("This file should only be included in Ruby 3.2 builds"); pub struct Definition; impl StableApiDefinition for Definition { #[inline] unsafe fn rstring_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; if !is_heap { rstring.as_.embed.len as _ } else { rstring.as_.heap.len } } #[inline] unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; let ptr = if !is_heap { std::ptr::addr_of!(rstring.as_.embed.ary) as *const _ } else { rstring.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] unsafe fn rarray_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; if is_embedded { let mut f = rarray.basic.flags; f &= crate::ruby_rarray_flags::RARRAY_EMBED_LEN_MASK as VALUE; f >>= crate::ruby_rarray_consts::RARRAY_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rarray.as_.heap.len } } #[inline] unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; let ptr = if is_embedded { std::ptr::addr_of!(rarray.as_.ary) as *const _ } else { rarray.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] fn special_const_p(&self, value: VALUE) -> bool { let is_immediate = (value) & (crate::special_consts::IMMEDIATE_MASK as VALUE) != 0; let test = (value & !(crate::Qnil as VALUE)) != 0; is_immediate || !test } #[inline] unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type { let rbasic = obj as *const crate::RBasic; let ret: u32 = ((*rbasic).flags & crate::ruby_value_type::RUBY_T_MASK as VALUE) as _; std::mem::transmute::<_, crate::ruby_value_type>(ret) } #[inline] fn nil_p(&self, obj: VALUE) -> bool { obj == (crate::Qnil as VALUE) } #[inline] fn fixnum_p(&self, obj: VALUE) -> bool { (obj & crate::FIXNUM_FLAG as VALUE) != 0 } #[inline] fn static_sym_p(&self, obj: VALUE) -> bool { let mask = !(VALUE::MAX << crate::ruby_special_consts::RUBY_SPECIAL_SHIFT as VALUE); (obj & mask) == crate::ruby_special_consts::RUBY_SYMBOL_FLAG as VALUE } #[inline] fn flonum_p(&self, obj: VALUE) -> bool { #[cfg(ruby_use_flonum = "true")] let ret = (obj & crate::FLONUM_MASK as VALUE) == crate::FLONUM_FLAG as VALUE; #[cfg(not(ruby_use_flonum = "true"))] let ret = false; ret } #[inline] fn immediate_p(&self, obj: VALUE) -> bool { (obj & crate::special_consts::IMMEDIATE_MASK as VALUE) != 0 } #[inline] fn rb_test(&self, obj: VALUE) -> bool { (obj & !(crate::Qnil as VALUE)) != 0 } #[inline] unsafe fn type_p(&self, obj: VALUE, t: crate::ruby_value_type) -> bool { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if t == RUBY_T_TRUE { obj == RUBY_Qtrue as _ } else if t == RUBY_T_FALSE { obj == RUBY_Qfalse as _ } else if t == RUBY_T_NIL { obj == RUBY_Qnil as _ } else if t == RUBY_T_UNDEF { obj == RUBY_Qundef as _ } else if t == RUBY_T_FIXNUM { self.fixnum_p(obj) } else if t == RUBY_T_SYMBOL { self.symbol_p(obj) } else if t == RUBY_T_FLOAT { self.float_type_p(obj) } else if self.special_const_p(obj) { false } else if t == self.builtin_type(obj) { true } else { t == self.rb_type(obj) } } #[inline] unsafe fn symbol_p(&self, obj: VALUE) -> bool { self.static_sym_p(obj) || self.dynamic_sym_p(obj) } #[inline] unsafe fn float_type_p(&self, obj: VALUE) -> bool { if self.flonum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_FLOAT } } #[inline] unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if !self.special_const_p(obj) { self.builtin_type(obj) } else if obj == RUBY_Qfalse as _ { RUBY_T_FALSE } else if obj == RUBY_Qnil as _ { RUBY_T_NIL } else if obj == RUBY_Qtrue as _ { RUBY_T_TRUE } else if obj == RUBY_Qundef as _ { RUBY_T_UNDEF } else if self.fixnum_p(obj) { RUBY_T_FIXNUM } else if self.static_sym_p(obj) { RUBY_T_SYMBOL } else { debug_assert!(self.flonum_p(obj)); RUBY_T_FLOAT } } #[inline] unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool { if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_SYMBOL } } #[inline] unsafe fn integer_type_p(&self, obj: VALUE) -> bool { if self.fixnum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_BIGNUM } } } rb-sys-0.9.97/src/stable_api/ruby_3_3.rs000064400000000000000000000143211046102023000160370ustar 00000000000000use super::StableApiDefinition; use crate::{ internal::{RArray, RString}, value_type, VALUE, }; use std::os::raw::{c_char, c_long}; #[cfg(not(ruby_eq_3_3))] compile_error!("This file should only be included in Ruby 3.3 builds"); pub struct Definition; impl StableApiDefinition for Definition { #[inline] unsafe fn rstring_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); rstring.len } #[inline] unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char { assert!(self.type_p(obj, crate::ruby_value_type::RUBY_T_STRING)); let rstring: &RString = &*(obj as *const RString); let flags = rstring.basic.flags; let is_heap = (flags & crate::ruby_rstring_flags::RSTRING_NOEMBED as VALUE) != 0; let ptr = if !is_heap { std::ptr::addr_of!(rstring.as_.embed.ary) as *const _ } else { rstring.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] unsafe fn rarray_len(&self, obj: VALUE) -> c_long { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; if is_embedded { let mut f = rarray.basic.flags; f &= crate::ruby_rarray_flags::RARRAY_EMBED_LEN_MASK as VALUE; f >>= crate::ruby_rarray_consts::RARRAY_EMBED_LEN_SHIFT as VALUE; f as c_long } else { rarray.as_.heap.len } } #[inline] unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE { assert!(self.type_p(obj, value_type::RUBY_T_ARRAY)); let rarray: &RArray = &*(obj as *const RArray); let flags = rarray.basic.flags; let is_embedded = (flags & crate::ruby_rarray_flags::RARRAY_EMBED_FLAG as VALUE) != 0; let ptr = if is_embedded { std::ptr::addr_of!(rarray.as_.ary) as *const _ } else { rarray.as_.heap.ptr }; assert!(!ptr.is_null()); ptr } #[inline] fn special_const_p(&self, value: VALUE) -> bool { let is_immediate = (value) & (crate::special_consts::IMMEDIATE_MASK as VALUE) != 0; let test = (value & !(crate::Qnil as VALUE)) != 0; is_immediate || !test } #[inline] unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type { let rbasic = obj as *const crate::RBasic; let ret: u32 = ((*rbasic).flags & crate::ruby_value_type::RUBY_T_MASK as VALUE) as _; std::mem::transmute::<_, crate::ruby_value_type>(ret) } #[inline] fn nil_p(&self, obj: VALUE) -> bool { obj == (crate::Qnil as VALUE) } #[inline] fn fixnum_p(&self, obj: VALUE) -> bool { (obj & crate::FIXNUM_FLAG as VALUE) != 0 } #[inline] fn static_sym_p(&self, obj: VALUE) -> bool { let mask = !(VALUE::MAX << crate::ruby_special_consts::RUBY_SPECIAL_SHIFT as VALUE); (obj & mask) == crate::ruby_special_consts::RUBY_SYMBOL_FLAG as VALUE } #[inline] fn flonum_p(&self, obj: VALUE) -> bool { #[cfg(ruby_use_flonum = "true")] let ret = (obj & crate::FLONUM_MASK as VALUE) == crate::FLONUM_FLAG as VALUE; #[cfg(not(ruby_use_flonum = "true"))] let ret = false; ret } #[inline] fn immediate_p(&self, obj: VALUE) -> bool { (obj & crate::special_consts::IMMEDIATE_MASK as VALUE) != 0 } #[inline] fn rb_test(&self, obj: VALUE) -> bool { (obj & !(crate::Qnil as VALUE)) != 0 } #[inline] unsafe fn type_p(&self, obj: VALUE, t: crate::ruby_value_type) -> bool { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if t == RUBY_T_TRUE { obj == RUBY_Qtrue as _ } else if t == RUBY_T_FALSE { obj == RUBY_Qfalse as _ } else if t == RUBY_T_NIL { obj == RUBY_Qnil as _ } else if t == RUBY_T_UNDEF { obj == RUBY_Qundef as _ } else if t == RUBY_T_FIXNUM { self.fixnum_p(obj) } else if t == RUBY_T_SYMBOL { self.symbol_p(obj) } else if t == RUBY_T_FLOAT { self.float_type_p(obj) } else if self.special_const_p(obj) { false } else if t == self.builtin_type(obj) { true } else { t == self.rb_type(obj) } } #[inline] unsafe fn symbol_p(&self, obj: VALUE) -> bool { self.static_sym_p(obj) || self.dynamic_sym_p(obj) } #[inline] unsafe fn float_type_p(&self, obj: VALUE) -> bool { if self.flonum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_FLOAT } } #[inline] unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type { use crate::ruby_special_consts::*; use crate::ruby_value_type::*; if !self.special_const_p(obj) { self.builtin_type(obj) } else if obj == RUBY_Qfalse as _ { RUBY_T_FALSE } else if obj == RUBY_Qnil as _ { RUBY_T_NIL } else if obj == RUBY_Qtrue as _ { RUBY_T_TRUE } else if obj == RUBY_Qundef as _ { RUBY_T_UNDEF } else if self.fixnum_p(obj) { RUBY_T_FIXNUM } else if self.static_sym_p(obj) { RUBY_T_SYMBOL } else { debug_assert!(self.flonum_p(obj)); RUBY_T_FLOAT } } #[inline] unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool { if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_SYMBOL } } #[inline] unsafe fn integer_type_p(&self, obj: VALUE) -> bool { if self.fixnum_p(obj) { true } else if self.special_const_p(obj) { false } else { self.builtin_type(obj) == value_type::RUBY_T_BIGNUM } } } rb-sys-0.9.97/src/stable_api.rs000064400000000000000000000141541046102023000144160ustar 00000000000000//! Stable ABI functions which provide access to Ruby internals that //! is compatible across Ruby versions, and are guaranteed to be not break due //! to Ruby binary changes. //! //! ### Goals //! //! 1. To provide access to Ruby internals that are not exposed by the libruby //! (i.e. C macros and inline functions). //! 2. Provide support for Ruby development versions, which can make breaking //! changes without semantic versioning. We want to support these versions //! to ensure Rust extensions don't prevent the Ruby core team from testing //! changes in production. use crate::VALUE; use std::os::raw::{c_char, c_long}; pub trait StableApiDefinition { /// Get the length of a Ruby string (akin to `RSTRING_LEN`). /// /// # Safety /// This function is unsafe because it dereferences a raw pointer to get /// access to underlying Ruby data. The caller must ensure that the pointer /// is valid. unsafe fn rstring_len(&self, obj: VALUE) -> c_long; /// Get a pointer to the bytes of a Ruby string (akin to `RSTRING_PTR`). /// /// # Safety /// This function is unsafe because it dereferences a raw pointer to get /// access to underlying Ruby data. The caller must ensure that the pointer /// is valid. unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char; /// Get the length of a Ruby array (akin to `RARRAY_LEN`). /// /// # Safety /// This function is unsafe because it dereferences a raw pointer to get /// access to underlying Ruby data. The caller must ensure that the pointer /// is valid. unsafe fn rarray_len(&self, obj: VALUE) -> c_long; /// Get a pointer to the elements of a Ruby array (akin to `RARRAY_CONST_PTR`). /// /// # Safety /// This function is unsafe because it dereferences a raw pointer to get /// access to underlying Ruby data. The caller must ensure that the pointer /// is valid. unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE; /// Tests if the given value is a special constant. fn special_const_p(&self, value: VALUE) -> bool; /// Queries the type of the object. /// /// # Note /// The input `obj` must not be a special constant. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type; /// Tests if the object's type is the given type. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. unsafe fn type_p(&self, obj: VALUE, ty: crate::ruby_value_type) -> bool; /// Checks if the given object is nil. fn nil_p(&self, obj: VALUE) -> bool; /// Checks if the given object is a so-called Fixnum. fn fixnum_p(&self, obj: VALUE) -> bool; /// Checks if the given object is a dynamic symbol. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool; /// Checks if the given object is a static symbol. fn static_sym_p(&self, obj: VALUE) -> bool; /// Checks if the given object is a symbol. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. unsafe fn symbol_p(&self, obj: VALUE) -> bool; /// Checks if the given object is a so-called Flonum. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. unsafe fn float_type_p(&self, obj: VALUE) -> bool; /// Checks if the given object is an integer type /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. unsafe fn integer_type_p(&self, obj: VALUE) -> bool; /// Checks if the given object is a so-called Flonum. fn flonum_p(&self, obj: VALUE) -> bool; /// Checks if the given object is an immediate i.e. an object which has /// no corresponding storage inside of the object space. fn immediate_p(&self, obj: VALUE) -> bool; /// Emulates Ruby's "if" statement by testing if the given `obj` is neither `Qnil` or `Qfalse`. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. fn rb_test(&self, ob: VALUE) -> bool; /// Queries the type of the object. Identical to `StableApi.builtin_type`, /// except it can also accept special constants. /// /// # Safety /// This function is unsafe because it could dereference a raw pointer when /// attemping to access the underlying [`RBasic`] struct. unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type; } #[cfg(stable_api_enable_compiled_mod)] mod compiled; #[cfg(stable_api_export_compiled_as_api)] use compiled as api; #[cfg(stable_api_include_rust_impl)] #[cfg_attr(ruby_eq_2_6, path = "stable_api/ruby_2_6.rs")] #[cfg_attr(ruby_eq_2_7, path = "stable_api/ruby_2_7.rs")] #[cfg_attr(ruby_eq_3_0, path = "stable_api/ruby_3_0.rs")] #[cfg_attr(ruby_eq_3_1, path = "stable_api/ruby_3_1.rs")] #[cfg_attr(ruby_eq_3_2, path = "stable_api/ruby_3_2.rs")] #[cfg_attr(ruby_eq_3_3, path = "stable_api/ruby_3_3.rs")] mod rust; #[cfg(not(stable_api_export_compiled_as_api))] use rust as api; /// Get the default stable API definition for the current Ruby version. pub const fn get_default() -> &'static api::Definition { const API: api::Definition = api::Definition {}; &API } /// Get the fallback stable API definition for the current Ruby version, which /// is compiled C code that is linked into to this crate. #[cfg(stable_api_enable_compiled_mod)] pub const fn get_compiled() -> &'static compiled::Definition { const COMPILED_API: compiled::Definition = compiled::Definition {}; &COMPILED_API } rb-sys-0.9.97/src/symbol.rs000064400000000000000000000017601046102023000136170ustar 00000000000000/// Finds or creates a symbol for the given static string. This macro will /// memoize the ID to avoid repeated calls to libruby. You should prefer this /// macro over [`rb_intern3`] when the string is known at compile time. /// /// # Safety /// /// This macro is safe under two conditions: /// - Ruby VM is initialized and that thus safe to call into libruby /// - The first call to this macro will be done inside of a managed Ruby thread (i.e. not a native thread) /// /// # Example /// /// ```no_run /// use rb_sys::{symbol::rb_intern, rb_funcall, rb_utf8_str_new}; /// /// unsafe { /// let reverse_id = rb_intern!("reverse"); /// let msg = rb_utf8_str_new("nice one".as_ptr() as *mut _, 4); /// rb_funcall(msg, reverse_id, 0); /// } /// ``` #[macro_export] macro_rules! rb_intern { ($s:literal) => {{ static mut ID: $crate::ID = 0; if ID == 0 { ID = $crate::rb_intern3($s.as_ptr() as _, $s.len() as _, $crate::rb_utf8_encoding()); } ID }}; } rb-sys-0.9.97/src/tracking_allocator.rs000064400000000000000000000157731046102023000161650ustar 00000000000000//! Support for reporting Rust memory usage to the Ruby GC. use crate::{rb_gc_adjust_memory_usage, utils::is_ruby_vm_started}; use std::{ alloc::{GlobalAlloc, Layout, System}, fmt::Formatter, sync::{ atomic::{AtomicIsize, Ordering}, Arc, }, }; /// A simple wrapper over [`std::alloc::System`] which reports memory usage to /// the Ruby GC. This gives the GC a more accurate picture of the process' /// memory usage so it can make better decisions about when to run. #[derive(Debug)] pub struct TrackingAllocator; impl TrackingAllocator { /// Create a new [`TrackingAllocator`]. pub const fn new() -> Self { Self } /// Create a new [`TrackingAllocator`] with default values. pub const fn default() -> Self { Self::new() } /// Adjust the memory usage reported to the Ruby GC by `delta`. Useful for /// tracking allocations invisible to the Rust allocator, such as `mmap` or /// direct `malloc` calls. /// /// # Example /// ``` /// use rb_sys::TrackingAllocator; /// /// // Allocate 1024 bytes of memory using `mmap` or `malloc`... /// TrackingAllocator::adjust_memory_usage(1024); /// /// // ...and then after the memory is freed, adjust the memory usage again. /// TrackingAllocator::adjust_memory_usage(-1024); /// ``` pub fn adjust_memory_usage(delta: isize) -> isize { if delta == 0 { return 0; } #[cfg(target_pointer_width = "32")] let delta = delta as i32; #[cfg(target_pointer_width = "64")] let delta = delta as i64; unsafe { if is_ruby_vm_started() { rb_gc_adjust_memory_usage(delta); delta as isize } else { 0 } } } } unsafe impl GlobalAlloc for TrackingAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { let ret = System.alloc(layout); let delta = layout.size() as isize; if !ret.is_null() && delta != 0 { Self::adjust_memory_usage(delta); } ret } unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let ret = System.alloc_zeroed(layout); let delta = layout.size() as isize; if !ret.is_null() && delta != 0 { Self::adjust_memory_usage(delta); } ret } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { System.dealloc(ptr, layout); let delta = -(layout.size() as isize); if delta != 0 { Self::adjust_memory_usage(delta); } } unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let ret = System.realloc(ptr, layout, new_size); let delta = new_size as isize - layout.size() as isize; if !ret.is_null() && delta != 0 { Self::adjust_memory_usage(delta); } ret } } /// Set the global allocator to [`TrackingAllocator`]. /// /// # Example /// ``` /// // File: ext/my_gem/src/lib.rs /// use rb_sys::set_global_tracking_allocator; /// /// set_global_tracking_allocator!(); /// ``` #[macro_export] macro_rules! set_global_tracking_allocator { () => { #[global_allocator] static RUBY_GLOBAL_TRACKING_ALLOCATOR: $crate::tracking_allocator::TrackingAllocator = $crate::tracking_allocator::TrackingAllocator; }; } #[derive(Debug)] #[repr(transparent)] struct MemsizeDelta(Arc); impl MemsizeDelta { fn new(delta: isize) -> Self { TrackingAllocator::adjust_memory_usage(delta); Self(Arc::new(AtomicIsize::new(delta))) } fn add(&self, delta: usize) { if delta == 0 { return; } self.0.fetch_add(delta as _, Ordering::SeqCst); TrackingAllocator::adjust_memory_usage(delta as _); } fn sub(&self, delta: usize) { if delta == 0 { return; } self.0.fetch_sub(delta as isize, Ordering::SeqCst); TrackingAllocator::adjust_memory_usage(-(delta as isize)); } fn get(&self) -> isize { self.0.load(Ordering::SeqCst) } } impl Clone for MemsizeDelta { fn clone(&self) -> Self { Self(Arc::clone(&self.0)) } } impl Drop for MemsizeDelta { fn drop(&mut self) { let memsize = self.0.swap(0, Ordering::SeqCst); TrackingAllocator::adjust_memory_usage(0 - memsize); } } /// A guard which adjusts the memory usage reported to the Ruby GC by `delta`. /// This allows you to track resources which are invisible to the Rust /// allocator, such as items that are known to internally use `mmap` or direct /// `malloc` in their implementation. /// /// Internally, it uses an [`Arc`] to track the memory usage delta, /// and is safe to clone when `T` is [`Clone`]. /// /// # Example /// ``` /// use rb_sys::tracking_allocator::ManuallyTracked; /// /// type SomethingThatUsedMmap = (); /// /// // Will tell the Ruby GC that 1024 bytes were allocated. /// let item = ManuallyTracked::new(SomethingThatUsedMmap, 1024); /// /// // Will tell the Ruby GC that 1024 bytes were freed. /// std::mem::drop(item); /// ``` pub struct ManuallyTracked { item: T, memsize_delta: MemsizeDelta, } impl ManuallyTracked { /// Create a new `ManuallyTracked`, and immediately report that `memsize` /// bytes were allocated. pub fn wrap(item: T, memsize: usize) -> Self { Self { item, memsize_delta: MemsizeDelta::new(memsize as _), } } /// Increase the memory usage reported to the Ruby GC by `memsize` bytes. pub fn increase_memory_usage(&self, memsize: usize) { self.memsize_delta.add(memsize); } /// Decrease the memory usage reported to the Ruby GC by `memsize` bytes. pub fn decrease_memory_usage(&self, memsize: usize) { self.memsize_delta.sub(memsize); } /// Get the current memory usage delta. pub fn memsize_delta(&self) -> isize { self.memsize_delta.get() } /// Get a shared reference to the inner `T`. pub fn get(&self) -> &T { &self.item } /// Get a mutable reference to the inner `T`. pub fn get_mut(&mut self) -> &mut T { &mut self.item } } impl ManuallyTracked<()> { /// Create a new `ManuallyTracked<()>`, and immediately report that /// `memsize` bytes were allocated. pub fn new(memsize: usize) -> Self { Self::wrap((), memsize) } } impl Default for ManuallyTracked<()> { fn default() -> Self { Self::wrap((), 0) } } impl Clone for ManuallyTracked { fn clone(&self) -> Self { Self { item: self.item.clone(), memsize_delta: self.memsize_delta.clone(), } } } impl std::fmt::Debug for ManuallyTracked { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("ManuallyTracked") .field("item", &self.item) .field("memsize_delta", &self.memsize_delta) .finish() } } rb-sys-0.9.97/src/utils.rs000064400000000000000000000036031046102023000134500ustar 00000000000000//! Internal utility functions. /// Check if the Ruby VM is globally available. /// /// Unfortunately there is no public API for this check, but there's a hidden /// `ruby_current_vm_ptr` symbol in libruby 2.5 - 3.2 which we can use to /// determine if the VM has been initialized, or shut down. /// /// # Notes /// /// Ruby 2.4 and below don't have a global VM pointer, so we can't check if it's /// null. Ruby 2.4 is EOL, and support will be dropped soon anyway. // /// In Ruby 3.3, the global VM pointer is no longer exported, so there's no /// simple way to check the global VM pointer, so instead we check if known /// static value is non-zero. /// /// On Ruby < 3.3, we also need to check if the global VM pointer is null to /// ensure the VM hasn't stopped, which makes the function name a bit of a /// misnomer... but in actuality this function can only guarantee that the /// VM is started, not that it's still running. pub(crate) unsafe fn is_ruby_vm_started() -> bool { #[cfg(all(ruby_gt_2_4, ruby_lte_3_2))] let ret = !crate::hidden::ruby_current_vm_ptr.is_null(); #[cfg(any(ruby_lte_2_4, ruby_gt_3_2))] let ret = crate::rb_cBasicObject != 0; ret } #[cfg(test)] mod tests { use super::*; use rusty_fork::rusty_fork_test; rusty_fork_test! { #[test] fn test_is_ruby_vm_started() { assert!(!unsafe { is_ruby_vm_started() }); #[cfg(windows)] { let mut argc = 0; let mut argv: [*mut std::os::raw::c_char; 0] = []; let mut argv = argv.as_mut_ptr(); unsafe { rb_sys::rb_w32_sysinit(&mut argc, &mut argv) }; } match unsafe { crate::ruby_setup() } { 0 => {} code => panic!("Failed to setup Ruby (error code: {})", code), }; assert!(unsafe { is_ruby_vm_started() }); } } } rb-sys-0.9.97/src/value_type.rs000064400000000000000000000003621046102023000144640ustar 00000000000000#![allow(rustdoc::broken_intra_doc_links)] //! Definitions for Ruby's special constants. //! //! Makes it easier to reference important Ruby constants, without havign to dig //! around in bindgen's output. pub use crate::ruby_value_type::*;