1 //! [![github]](https://github.com/dtolnay/cxx) [![crates-io]](https://crates.io/crates/cxx) [![docs-rs]](https://docs.rs/cxx) 2 //! 3 //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github 4 //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust 5 //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K 6 //! 7 //! <br> 8 //! 9 //! This library provides a **safe** mechanism for calling C++ code from Rust 10 //! and Rust code from C++, not subject to the many ways that things can go 11 //! wrong when using bindgen or cbindgen to generate unsafe C-style bindings. 12 //! 13 //! This doesn't change the fact that 100% of C++ code is unsafe. When auditing 14 //! a project, you would be on the hook for auditing all the unsafe Rust code 15 //! and *all* the C++ code. The core safety claim under this new model is that 16 //! auditing just the C++ side would be sufficient to catch all problems, i.e. 17 //! the Rust side can be 100% safe. 18 //! 19 //! <br> 20 //! 21 //! *Compiler support: requires rustc 1.48+ and c++11 or newer*<br> 22 //! *[Release notes](https://github.com/dtolnay/cxx/releases)* 23 //! 24 //! <br> 25 //! 26 //! # Guide 27 //! 28 //! Please see **<https://cxx.rs>** for a tutorial, reference material, and 29 //! example code. 30 //! 31 //! <br> 32 //! 33 //! # Overview 34 //! 35 //! The idea is that we define the signatures of both sides of our FFI boundary 36 //! embedded together in one Rust module (the next section shows an example). 37 //! From this, CXX receives a complete picture of the boundary to perform static 38 //! analyses against the types and function signatures to uphold both Rust's and 39 //! C++'s invariants and requirements. 40 //! 41 //! If everything checks out statically, then CXX uses a pair of code generators 42 //! to emit the relevant `extern "C"` signatures on both sides together with any 43 //! necessary static assertions for later in the build process to verify 44 //! correctness. On the Rust side this code generator is simply an attribute 45 //! procedural macro. On the C++ side it can be a small Cargo build script if 46 //! your build is managed by Cargo, or for other build systems like Bazel or 47 //! Buck we provide a command line tool which generates the header and source 48 //! file and should be easy to integrate. 49 //! 50 //! The resulting FFI bridge operates at zero or negligible overhead, i.e. no 51 //! copying, no serialization, no memory allocation, no runtime checks needed. 52 //! 53 //! The FFI signatures are able to use native types from whichever side they 54 //! please, such as Rust's `String` or C++'s `std::string`, Rust's `Box` or 55 //! C++'s `std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any 56 //! combination. CXX guarantees an ABI-compatible signature that both sides 57 //! understand, based on builtin bindings for key standard library types to 58 //! expose an idiomatic API on those types to the other language. For example 59 //! when manipulating a C++ string from Rust, its `len()` method becomes a call 60 //! of the `size()` member function defined by C++; when manipulation a Rust 61 //! string from C++, its `size()` member function calls Rust's `len()`. 62 //! 63 //! <br> 64 //! 65 //! # Example 66 //! 67 //! In this example we are writing a Rust application that wishes to take 68 //! advantage of an existing C++ client for a large-file blobstore service. The 69 //! blobstore supports a `put` operation for a discontiguous buffer upload. For 70 //! example we might be uploading snapshots of a circular buffer which would 71 //! tend to consist of 2 chunks, or fragments of a file spread across memory for 72 //! some other reason. 73 //! 74 //! A runnable version of this example is provided under the *demo* directory of 75 //! <https://github.com/dtolnay/cxx>. To try it out, run `cargo run` from that 76 //! directory. 77 //! 78 //! ```no_run 79 //! #[cxx::bridge] 80 //! mod ffi { 81 //! // Any shared structs, whose fields will be visible to both languages. 82 //! struct BlobMetadata { 83 //! size: usize, 84 //! tags: Vec<String>, 85 //! } 86 //! 87 //! extern "Rust" { 88 //! // Zero or more opaque types which both languages can pass around but 89 //! // only Rust can see the fields. 90 //! type MultiBuf; 91 //! 92 //! // Functions implemented in Rust. 93 //! fn next_chunk(buf: &mut MultiBuf) -> &[u8]; 94 //! } 95 //! 96 //! unsafe extern "C++" { 97 //! // One or more headers with the matching C++ declarations. Our code 98 //! // generators don't read it but it gets #include'd and used in static 99 //! // assertions to ensure our picture of the FFI boundary is accurate. 100 //! include!("demo/include/blobstore.h"); 101 //! 102 //! // Zero or more opaque types which both languages can pass around but 103 //! // only C++ can see the fields. 104 //! type BlobstoreClient; 105 //! 106 //! // Functions implemented in C++. 107 //! fn new_blobstore_client() -> UniquePtr<BlobstoreClient>; 108 //! fn put(&self, parts: &mut MultiBuf) -> u64; 109 //! fn tag(&self, blobid: u64, tag: &str); 110 //! fn metadata(&self, blobid: u64) -> BlobMetadata; 111 //! } 112 //! } 113 //! # 114 //! # pub struct MultiBuf; 115 //! # 116 //! # fn next_chunk(_buf: &mut MultiBuf) -> &[u8] { 117 //! # unimplemented!() 118 //! # } 119 //! # 120 //! # fn main() {} 121 //! ``` 122 //! 123 //! Now we simply provide Rust definitions of all the things in the `extern 124 //! "Rust"` block and C++ definitions of all the things in the `extern "C++"` 125 //! block, and get to call back and forth safely. 126 //! 127 //! Here are links to the complete set of source files involved in the demo: 128 //! 129 //! - [demo/src/main.rs](https://github.com/dtolnay/cxx/blob/master/demo/src/main.rs) 130 //! - [demo/build.rs](https://github.com/dtolnay/cxx/blob/master/demo/build.rs) 131 //! - [demo/include/blobstore.h](https://github.com/dtolnay/cxx/blob/master/demo/include/blobstore.h) 132 //! - [demo/src/blobstore.cc](https://github.com/dtolnay/cxx/blob/master/demo/src/blobstore.cc) 133 //! 134 //! To look at the code generated in both languages for the example by the CXX 135 //! code generators: 136 //! 137 //! ```console 138 //! # run Rust code generator and print to stdout 139 //! # (requires https://github.com/dtolnay/cargo-expand) 140 //! $ cargo expand --manifest-path demo/Cargo.toml 141 //! 142 //! # run C++ code generator and print to stdout 143 //! $ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs 144 //! ``` 145 //! 146 //! <br> 147 //! 148 //! # Details 149 //! 150 //! As seen in the example, the language of the FFI boundary involves 3 kinds of 151 //! items: 152 //! 153 //! - **Shared structs** — their fields are made visible to both 154 //! languages. The definition written within cxx::bridge is the single source 155 //! of truth. 156 //! 157 //! - **Opaque types** — their fields are secret from the other language. 158 //! These cannot be passed across the FFI by value but only behind an 159 //! indirection, such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can 160 //! be a type alias for an arbitrarily complicated generic language-specific 161 //! type depending on your use case. 162 //! 163 //! - **Functions** — implemented in either language, callable from the 164 //! other language. 165 //! 166 //! Within the `extern "Rust"` part of the CXX bridge we list the types and 167 //! functions for which Rust is the source of truth. These all implicitly refer 168 //! to the `super` module, the parent module of the CXX bridge. You can think of 169 //! the two items listed in the example above as being like `use 170 //! super::MultiBuf` and `use super::next_chunk` except re-exported to C++. The 171 //! parent module will either contain the definitions directly for simple 172 //! things, or contain the relevant `use` statements to bring them into scope 173 //! from elsewhere. 174 //! 175 //! Within the `extern "C++"` part, we list types and functions for which C++ is 176 //! the source of truth, as well as the header(s) that declare those APIs. In 177 //! the future it's possible that this section could be generated bindgen-style 178 //! from the headers but for now we need the signatures written out; static 179 //! assertions will verify that they are accurate. 180 //! 181 //! Your function implementations themselves, whether in C++ or Rust, *do not* 182 //! need to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the 183 //! right shims where necessary to make it all work. 184 //! 185 //! <br> 186 //! 187 //! # Comparison vs bindgen and cbindgen 188 //! 189 //! Notice that with CXX there is repetition of all the function signatures: 190 //! they are typed out once where the implementation is defined (in C++ or Rust) 191 //! and again inside the cxx::bridge module, though compile-time assertions 192 //! guarantee these are kept in sync. This is different from [bindgen] and 193 //! [cbindgen] where function signatures are typed by a human once and the tool 194 //! consumes them in one language and emits them in the other language. 195 //! 196 //! [bindgen]: https://github.com/rust-lang/rust-bindgen 197 //! [cbindgen]: https://github.com/eqrion/cbindgen/ 198 //! 199 //! This is because CXX fills a somewhat different role. It is a lower level 200 //! tool than bindgen or cbindgen in a sense; you can think of it as being a 201 //! replacement for the concept of `extern "C"` signatures as we know them, 202 //! rather than a replacement for a bindgen. It would be reasonable to build a 203 //! higher level bindgen-like tool on top of CXX which consumes a C++ header 204 //! and/or Rust module (and/or IDL like Thrift) as source of truth and generates 205 //! the cxx::bridge, eliminating the repetition while leveraging the static 206 //! analysis safety guarantees of CXX. 207 //! 208 //! But note in other ways CXX is higher level than the bindgens, with rich 209 //! support for common standard library types. Frequently with bindgen when we 210 //! are dealing with an idiomatic C++ API we would end up manually wrapping that 211 //! API in C-style raw pointer functions, applying bindgen to get unsafe raw 212 //! pointer Rust functions, and replicating the API again to expose those 213 //! idiomatically in Rust. That's a much worse form of repetition because it is 214 //! unsafe all the way through. 215 //! 216 //! By using a CXX bridge as the shared understanding between the languages, 217 //! rather than `extern "C"` C-style signatures as the shared understanding, 218 //! common FFI use cases become expressible using 100% safe code. 219 //! 220 //! It would also be reasonable to mix and match, using CXX bridge for the 95% 221 //! of your FFI that is straightforward and doing the remaining few oddball 222 //! signatures the old fashioned way with bindgen and cbindgen, if for some 223 //! reason CXX's static restrictions get in the way. Please file an issue if you 224 //! end up taking this approach so that we know what ways it would be worthwhile 225 //! to make the tool more expressive. 226 //! 227 //! <br> 228 //! 229 //! # Cargo-based setup 230 //! 231 //! For builds that are orchestrated by Cargo, you will use a build script that 232 //! runs CXX's C++ code generator and compiles the resulting C++ code along with 233 //! any other C++ code for your crate. 234 //! 235 //! The canonical build script is as follows. The indicated line returns a 236 //! [`cc::Build`] instance (from the usual widely used `cc` crate) on which you 237 //! can set up any additional source files and compiler flags as normal. 238 //! 239 //! [`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html 240 //! 241 //! ```toml 242 //! # Cargo.toml 243 //! 244 //! [build-dependencies] 245 //! cxx-build = "1.0" 246 //! ``` 247 //! 248 //! ```no_run 249 //! // build.rs 250 //! 251 //! fn main() { 252 //! cxx_build::bridge("src/main.rs") // returns a cc::Build 253 //! .file("src/demo.cc") 254 //! .flag_if_supported("-std=c++11") 255 //! .compile("cxxbridge-demo"); 256 //! 257 //! println!("cargo:rerun-if-changed=src/main.rs"); 258 //! println!("cargo:rerun-if-changed=src/demo.cc"); 259 //! println!("cargo:rerun-if-changed=include/demo.h"); 260 //! } 261 //! ``` 262 //! 263 //! <br><br> 264 //! 265 //! # Non-Cargo setup 266 //! 267 //! For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate 268 //! way of invoking the C++ code generator as a standalone command line tool. 269 //! The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be 270 //! built from the *gen/cmd* directory of <https://github.com/dtolnay/cxx>. 271 //! 272 //! ```bash 273 //! $ cargo install cxxbridge-cmd 274 //! 275 //! $ cxxbridge src/main.rs --header > path/to/mybridge.h 276 //! $ cxxbridge src/main.rs > path/to/mybridge.cc 277 //! ``` 278 //! 279 //! <br> 280 //! 281 //! # Safety 282 //! 283 //! Be aware that the design of this library is intentionally restrictive and 284 //! opinionated! It isn't a goal to be powerful enough to handle arbitrary 285 //! signatures in either language. Instead this project is about carving out a 286 //! reasonably expressive set of functionality about which we can make useful 287 //! safety guarantees today and maybe extend over time. You may find that it 288 //! takes some practice to use CXX bridge effectively as it won't work in all 289 //! the ways that you are used to. 290 //! 291 //! Some of the considerations that go into ensuring safety are: 292 //! 293 //! - By design, our paired code generators work together to control both sides 294 //! of the FFI boundary. Ordinarily in Rust writing your own `extern "C"` 295 //! blocks is unsafe because the Rust compiler has no way to know whether the 296 //! signatures you've written actually match the signatures implemented in the 297 //! other language. With CXX we achieve that visibility and know what's on the 298 //! other side. 299 //! 300 //! - Our static analysis detects and prevents passing types by value that 301 //! shouldn't be passed by value from C++ to Rust, for example because they 302 //! may contain internal pointers that would be screwed up by Rust's move 303 //! behavior. 304 //! 305 //! - To many people's surprise, it is possible to have a struct in Rust and a 306 //! struct in C++ with exactly the same layout / fields / alignment / 307 //! everything, and still not the same ABI when passed by value. This is a 308 //! longstanding bindgen bug that leads to segfaults in absolutely 309 //! correct-looking code ([rust-lang/rust-bindgen#778]). CXX knows about this 310 //! and can insert the necessary zero-cost workaround transparently where 311 //! needed, so go ahead and pass your structs by value without worries. This 312 //! is made possible by owning both sides of the boundary rather than just 313 //! one. 314 //! 315 //! - Template instantiations: for example in order to expose a UniquePtr\<T\> 316 //! type in Rust backed by a real C++ unique\_ptr, we have a way of using a 317 //! Rust trait to connect the behavior back to the template instantiations 318 //! performed by the other language. 319 //! 320 //! [rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778 321 //! 322 //! <br> 323 //! 324 //! # Builtin types 325 //! 326 //! In addition to all the primitive types (i32 <=> int32_t), the 327 //! following common types may be used in the fields of shared structs and the 328 //! arguments and returns of functions. 329 //! 330 //! <table> 331 //! <tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr> 332 //! <tr><td>String</td><td>rust::String</td><td></td></tr> 333 //! <tr><td>&str</td><td>rust::Str</td><td></td></tr> 334 //! <tr><td>&[T]</td><td>rust::Slice<const T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 335 //! <tr><td>&mut [T]</td><td>rust::Slice<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 336 //! <tr><td><a href="struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr> 337 //! <tr><td>Box<T></td><td>rust::Box<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 338 //! <tr><td><a href="struct.UniquePtr.html">UniquePtr<T></a></td><td>std::unique_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr> 339 //! <tr><td><a href="struct.SharedPtr.html">SharedPtr<T></a></td><td>std::shared_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr> 340 //! <tr><td>[T; N]</td><td>std::array<T, N></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 341 //! <tr><td>Vec<T></td><td>rust::Vec<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 342 //! <tr><td><a href="struct.CxxVector.html">CxxVector<T></a></td><td>std::vector<T></td><td><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr> 343 //! <tr><td>*mut T, *const T</td><td>T*, const T*</td><td><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr> 344 //! <tr><td>fn(T, U) -> V</td><td>rust::Fn<V(T, U)></td><td><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr> 345 //! <tr><td>Result<T></td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr> 346 //! </table> 347 //! 348 //! The C++ API of the `rust` namespace is defined by the *include/cxx.h* file 349 //! in <https://github.com/dtolnay/cxx>. You will need to include this header in 350 //! your C++ code when working with those types. 351 //! 352 //! The following types are intended to be supported "soon" but are just not 353 //! implemented yet. I don't expect any of these to be hard to make work but 354 //! it's a matter of designing a nice API for each in its non-native language. 355 //! 356 //! <table> 357 //! <tr><th>name in Rust</th><th>name in C++</th></tr> 358 //! <tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 359 //! <tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 360 //! <tr><td>Arc<T></td><td><sup><i>tbd</i></sup></td></tr> 361 //! <tr><td>Option<T></td><td><sup><i>tbd</i></sup></td></tr> 362 //! <tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr> 363 //! <tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr> 364 //! </table> 365 366 #![no_std] 367 #![doc(html_root_url = "https://docs.rs/cxx/1.0.42")] 368 #![deny(improper_ctypes)] 369 #![allow(non_camel_case_types)] 370 #![allow( 371 clippy::cognitive_complexity, 372 clippy::declare_interior_mutable_const, 373 clippy::doc_markdown, 374 clippy::empty_enum, 375 clippy::inherent_to_string, 376 clippy::items_after_statements, 377 clippy::large_enum_variant, 378 clippy::len_without_is_empty, 379 clippy::missing_errors_doc, 380 clippy::missing_safety_doc, 381 clippy::module_inception, 382 clippy::module_name_repetitions, 383 clippy::must_use_candidate, 384 clippy::needless_doctest_main, 385 clippy::new_without_default, 386 clippy::or_fun_call, 387 clippy::ptr_arg, 388 clippy::toplevel_ref_arg, 389 clippy::useless_let_if_seq, 390 clippy::wrong_self_convention 391 )] 392 393 #[cfg(built_with_cargo)] 394 extern crate link_cplusplus; 395 396 extern crate alloc; 397 extern crate self as cxx; 398 extern crate std; 399 400 #[macro_use] 401 mod macros; 402 403 mod cxx_vector; 404 mod exception; 405 mod extern_type; 406 mod fmt; 407 mod function; 408 pub mod memory; 409 mod opaque; 410 mod result; 411 mod rust_slice; 412 mod rust_str; 413 mod rust_string; 414 mod rust_type; 415 mod rust_vec; 416 mod shared_ptr; 417 #[path = "cxx_string.rs"] 418 mod string; 419 mod symbols; 420 mod type_id; 421 mod unique_ptr; 422 mod unwind; 423 pub mod vector; 424 mod weak_ptr; 425 426 pub use crate::cxx_vector::CxxVector; 427 pub use crate::exception::Exception; 428 pub use crate::extern_type::{kind, ExternType}; 429 pub use crate::shared_ptr::SharedPtr; 430 pub use crate::string::CxxString; 431 pub use crate::unique_ptr::UniquePtr; 432 pub use crate::weak_ptr::WeakPtr; 433 pub use cxxbridge_macro::bridge; 434 435 /// Synonym for `CxxString`. 436 /// 437 /// To avoid confusion with Rust's standard library string you probably 438 /// shouldn't import this type with `use`. Instead, write `cxx::String`, or 439 /// import and use `CxxString`. 440 pub type String = CxxString; 441 442 /// Synonym for `CxxVector`. 443 /// 444 /// To avoid confusion with Rust's standard library vector you probably 445 /// shouldn't import this type with `use`. Instead, write `cxx::Vector<T>`, or 446 /// import and use `CxxVector`. 447 pub type Vector<T> = CxxVector<T>; 448 449 // Not public API. 450 #[doc(hidden)] 451 pub mod private { 452 pub use crate::cxx_vector::VectorElement; 453 pub use crate::extern_type::{verify_extern_kind, verify_extern_type}; 454 pub use crate::function::FatFunction; 455 pub use crate::opaque::Opaque; 456 pub use crate::result::{r#try, Result}; 457 pub use crate::rust_slice::RustSlice; 458 pub use crate::rust_str::RustStr; 459 pub use crate::rust_string::RustString; 460 pub use crate::rust_type::{ImplBox, ImplVec, RustType}; 461 pub use crate::rust_vec::RustVec; 462 pub use crate::shared_ptr::SharedPtrTarget; 463 pub use crate::string::StackString; 464 pub use crate::unique_ptr::UniquePtrTarget; 465 pub use crate::unwind::catch_unwind; 466 pub use crate::weak_ptr::WeakPtrTarget; 467 pub use cxxbridge_macro::type_id; 468 } 469 470 mod actually_private { 471 pub trait Private {} 472 } 473 474 macro_rules! chars { 475 ($($ch:ident)*) => { 476 $( 477 #[doc(hidden)] 478 pub enum $ch {} 479 )* 480 }; 481 } 482 483 chars! { 484 _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 485 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 486 a b c d e f g h i j k l m n o p q r s t u v w x y z 487 __ // underscore 488 } 489