aboutsummaryrefslogtreecommitdiff
path: root/crates/proc_macro_srv/src/rustc_server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/proc_macro_srv/src/rustc_server.rs')
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs704
1 files changed, 704 insertions, 0 deletions
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
new file mode 100644
index 000000000..d534d1337
--- /dev/null
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -0,0 +1,704 @@
1//! Rustc proc-macro server implementation with tt
2//!
3//! Based on idea from https://github.com/fedochet/rust-proc-macro-expander
4//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that
5//! we could provide any TokenStream implementation.
6//! The original idea from fedochet is using proc-macro2 as backend,
7//! we use tt instead for better intergation with RA.
8//!
9//! FIXME: No span and source file information is implemented yet
10
11use crate::proc_macro::bridge::{self, server};
12
13use std::collections::{Bound, HashMap};
14use std::hash::Hash;
15use std::iter::FromIterator;
16use std::str::FromStr;
17use std::{ascii, vec::IntoIter};
18
19type Group = tt::Subtree;
20type TokenTree = tt::TokenTree;
21type Punct = tt::Punct;
22type Spacing = tt::Spacing;
23type Literal = tt::Literal;
24type Span = tt::TokenId;
25
26#[derive(Debug, Clone)]
27pub struct TokenStream {
28 pub subtree: tt::Subtree,
29}
30
31impl TokenStream {
32 pub fn new() -> Self {
33 TokenStream { subtree: Default::default() }
34 }
35
36 pub fn with_subtree(subtree: tt::Subtree) -> Self {
37 TokenStream { subtree }
38 }
39
40 pub fn is_empty(&self) -> bool {
41 self.subtree.token_trees.is_empty()
42 }
43}
44
45/// Creates a token stream containing a single token tree.
46impl From<TokenTree> for TokenStream {
47 fn from(tree: TokenTree) -> TokenStream {
48 TokenStream { subtree: tt::Subtree { delimiter: None, token_trees: vec![tree] } }
49 }
50}
51
52/// Collects a number of token trees into a single stream.
53impl FromIterator<TokenTree> for TokenStream {
54 fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
55 trees.into_iter().map(TokenStream::from).collect()
56 }
57}
58
59/// A "flattening" operation on token streams, collects token trees
60/// from multiple token streams into a single stream.
61impl FromIterator<TokenStream> for TokenStream {
62 fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
63 let mut builder = TokenStreamBuilder::new();
64 streams.into_iter().for_each(|stream| builder.push(stream));
65 builder.build()
66 }
67}
68
69impl Extend<TokenTree> for TokenStream {
70 fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, trees: I) {
71 self.extend(trees.into_iter().map(TokenStream::from));
72 }
73}
74
75impl Extend<TokenStream> for TokenStream {
76 fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
77 for item in streams {
78 for tkn in item {
79 match tkn {
80 tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => {
81 self.subtree.token_trees.extend(subtree.token_trees);
82 }
83 _ => {
84 self.subtree.token_trees.push(tkn);
85 }
86 }
87 }
88 }
89 }
90}
91
92type Level = crate::proc_macro::Level;
93type LineColumn = crate::proc_macro::LineColumn;
94type SourceFile = crate::proc_macro::SourceFile;
95
96/// A structure representing a diagnostic message and associated children
97/// messages.
98#[derive(Clone, Debug)]
99pub struct Diagnostic {
100 level: Level,
101 message: String,
102 spans: Vec<Span>,
103 children: Vec<Diagnostic>,
104}
105
106impl Diagnostic {
107 /// Creates a new diagnostic with the given `level` and `message`.
108 pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
109 Diagnostic { level, message: message.into(), spans: vec![], children: vec![] }
110 }
111}
112
113// Rustc Server Ident has to be `Copyable`
114// We use a stub here for bypassing
115#[derive(Hash, Eq, PartialEq, Copy, Clone)]
116pub struct IdentId(u32);
117
118#[derive(Clone, Hash, Eq, PartialEq)]
119struct IdentData(tt::Ident);
120
121#[derive(Default)]
122struct IdentInterner {
123 idents: HashMap<IdentData, u32>,
124 ident_data: Vec<IdentData>,
125}
126
127impl IdentInterner {
128 fn intern(&mut self, data: &IdentData) -> u32 {
129 if let Some(index) = self.idents.get(data) {
130 return *index;
131 }
132
133 let index = self.idents.len() as u32;
134 self.ident_data.push(data.clone());
135 self.idents.insert(data.clone(), index);
136 index
137 }
138
139 fn get(&self, index: u32) -> &IdentData {
140 &self.ident_data[index as usize]
141 }
142
143 #[allow(unused)]
144 fn get_mut(&mut self, index: u32) -> &mut IdentData {
145 self.ident_data.get_mut(index as usize).expect("Should be consistent")
146 }
147}
148
149pub struct TokenStreamBuilder {
150 acc: TokenStream,
151}
152
153/// Public implementation details for the `TokenStream` type, such as iterators.
154pub mod token_stream {
155 use std::str::FromStr;
156
157 use super::{TokenStream, TokenTree};
158
159 /// An iterator over `TokenStream`'s `TokenTree`s.
160 /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
161 /// and returns whole groups as token trees.
162 impl IntoIterator for TokenStream {
163 type Item = TokenTree;
164 type IntoIter = super::IntoIter<TokenTree>;
165
166 fn into_iter(self) -> Self::IntoIter {
167 self.subtree.token_trees.into_iter()
168 }
169 }
170
171 type LexError = String;
172
173 /// Attempts to break the string into tokens and parse those tokens into a token stream.
174 /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters
175 /// or characters not existing in the language.
176 /// All tokens in the parsed stream get `Span::call_site()` spans.
177 ///
178 /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to
179 /// change these errors into `LexError`s later.
180 impl FromStr for TokenStream {
181 type Err = LexError;
182
183 fn from_str(src: &str) -> Result<TokenStream, LexError> {
184 let (subtree, _token_map) =
185 ra_mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
186
187 let tt: tt::TokenTree = subtree.into();
188 Ok(tt.into())
189 }
190 }
191
192 impl ToString for TokenStream {
193 fn to_string(&self) -> String {
194 let tt = self.subtree.clone().into();
195 to_text(&tt)
196 }
197 }
198
199 fn to_text(tkn: &tt::TokenTree) -> String {
200 match tkn {
201 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
202 tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
203 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
204 tt::TokenTree::Subtree(subtree) => {
205 let content = subtree
206 .token_trees
207 .iter()
208 .map(|tkn| {
209 let s = to_text(tkn);
210 if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
211 if punct.spacing == tt::Spacing::Alone {
212 return s + " ";
213 }
214 }
215 s
216 })
217 .collect::<Vec<_>>()
218 .concat();
219 let (open, close) = match subtree.delimiter.map(|it| it.kind) {
220 None => ("", ""),
221 Some(tt::DelimiterKind::Brace) => ("{", "}"),
222 Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
223 Some(tt::DelimiterKind::Bracket) => ("[", "]"),
224 };
225 format!("{}{}{}", open, content, close)
226 }
227 }
228 }
229}
230
231impl TokenStreamBuilder {
232 fn new() -> TokenStreamBuilder {
233 TokenStreamBuilder { acc: TokenStream::new() }
234 }
235
236 fn push(&mut self, stream: TokenStream) {
237 self.acc.extend(stream.into_iter())
238 }
239
240 fn build(self) -> TokenStream {
241 self.acc
242 }
243}
244
245#[derive(Clone)]
246pub struct TokenStreamIter {
247 trees: IntoIter<TokenTree>,
248}
249
250#[derive(Default)]
251pub struct Rustc {
252 ident_interner: IdentInterner,
253 // FIXME: store span information here.
254}
255
256impl server::Types for Rustc {
257 type TokenStream = TokenStream;
258 type TokenStreamBuilder = TokenStreamBuilder;
259 type TokenStreamIter = TokenStreamIter;
260 type Group = Group;
261 type Punct = Punct;
262 type Ident = IdentId;
263 type Literal = Literal;
264 type SourceFile = SourceFile;
265 type Diagnostic = Diagnostic;
266 type Span = Span;
267 type MultiSpan = Vec<Span>;
268}
269
270impl server::TokenStream for Rustc {
271 fn new(&mut self) -> Self::TokenStream {
272 Self::TokenStream::new()
273 }
274
275 fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
276 stream.is_empty()
277 }
278 fn from_str(&mut self, src: &str) -> Self::TokenStream {
279 Self::TokenStream::from_str(src).expect("cannot parse string")
280 }
281 fn to_string(&mut self, stream: &Self::TokenStream) -> String {
282 stream.to_string()
283 }
284 fn from_token_tree(
285 &mut self,
286 tree: bridge::TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
287 ) -> Self::TokenStream {
288 match tree {
289 bridge::TokenTree::Group(group) => {
290 let tree = TokenTree::from(group);
291 Self::TokenStream::from_iter(vec![tree])
292 }
293
294 bridge::TokenTree::Ident(IdentId(index)) => {
295 let IdentData(ident) = self.ident_interner.get(index).clone();
296 let ident: tt::Ident = ident;
297 let leaf = tt::Leaf::from(ident);
298 let tree = TokenTree::from(leaf);
299 Self::TokenStream::from_iter(vec![tree])
300 }
301
302 bridge::TokenTree::Literal(literal) => {
303 let leaf = tt::Leaf::from(literal);
304 let tree = TokenTree::from(leaf);
305 Self::TokenStream::from_iter(vec![tree])
306 }
307
308 bridge::TokenTree::Punct(p) => {
309 let leaf = tt::Leaf::from(p);
310 let tree = TokenTree::from(leaf);
311 Self::TokenStream::from_iter(vec![tree])
312 }
313 }
314 }
315
316 fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
317 let trees: Vec<TokenTree> = stream.into_iter().collect();
318 TokenStreamIter { trees: trees.into_iter() }
319 }
320}
321
322impl server::TokenStreamBuilder for Rustc {
323 fn new(&mut self) -> Self::TokenStreamBuilder {
324 Self::TokenStreamBuilder::new()
325 }
326 fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
327 builder.push(stream)
328 }
329 fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
330 builder.build()
331 }
332}
333
334impl server::TokenStreamIter for Rustc {
335 fn next(
336 &mut self,
337 iter: &mut Self::TokenStreamIter,
338 ) -> Option<bridge::TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
339 iter.trees.next().map(|tree| match tree {
340 TokenTree::Subtree(group) => bridge::TokenTree::Group(group),
341 TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
342 bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident))))
343 }
344 TokenTree::Leaf(tt::Leaf::Literal(literal)) => bridge::TokenTree::Literal(literal),
345 TokenTree::Leaf(tt::Leaf::Punct(punct)) => bridge::TokenTree::Punct(punct),
346 })
347 }
348}
349
350fn delim_to_internal(d: bridge::Delimiter) -> Option<tt::Delimiter> {
351 let kind = match d {
352 bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
353 bridge::Delimiter::Brace => tt::DelimiterKind::Brace,
354 bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket,
355 bridge::Delimiter::None => return None,
356 };
357 Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind })
358}
359
360fn delim_to_external(d: Option<tt::Delimiter>) -> bridge::Delimiter {
361 match d.map(|it| it.kind) {
362 Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis,
363 Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace,
364 Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket,
365 None => bridge::Delimiter::None,
366 }
367}
368
369fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing {
370 match spacing {
371 bridge::Spacing::Alone => Spacing::Alone,
372 bridge::Spacing::Joint => Spacing::Joint,
373 }
374}
375
376fn spacing_to_external(spacing: Spacing) -> bridge::Spacing {
377 match spacing {
378 Spacing::Alone => bridge::Spacing::Alone,
379 Spacing::Joint => bridge::Spacing::Joint,
380 }
381}
382
383impl server::Group for Rustc {
384 fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group {
385 Self::Group {
386 delimiter: delim_to_internal(delimiter),
387 token_trees: stream.subtree.token_trees,
388 }
389 }
390 fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter {
391 delim_to_external(group.delimiter)
392 }
393
394 // NOTE: Return value of do not include delimiter
395 fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
396 TokenStream {
397 subtree: tt::Subtree { delimiter: None, token_trees: group.token_trees.clone() },
398 }
399 }
400
401 fn span(&mut self, group: &Self::Group) -> Self::Span {
402 group.delimiter.map(|it| it.id).unwrap_or_else(|| tt::TokenId::unspecified())
403 }
404
405 fn set_span(&mut self, _group: &mut Self::Group, _span: Self::Span) {
406 // FIXME handle span
407 }
408
409 fn span_open(&mut self, _group: &Self::Group) -> Self::Span {
410 // FIXME handle span
411 // MySpan(self.span_interner.intern(&MySpanData(group.span_open())))
412 tt::TokenId::unspecified()
413 }
414
415 fn span_close(&mut self, _group: &Self::Group) -> Self::Span {
416 // FIXME handle span
417 tt::TokenId::unspecified()
418 }
419}
420
421impl server::Punct for Rustc {
422 fn new(&mut self, ch: char, spacing: bridge::Spacing) -> Self::Punct {
423 tt::Punct {
424 char: ch,
425 spacing: spacing_to_internal(spacing),
426 id: tt::TokenId::unspecified(),
427 }
428 }
429 fn as_char(&mut self, punct: Self::Punct) -> char {
430 punct.char
431 }
432 fn spacing(&mut self, punct: Self::Punct) -> bridge::Spacing {
433 spacing_to_external(punct.spacing)
434 }
435 fn span(&mut self, _punct: Self::Punct) -> Self::Span {
436 // FIXME handle span
437 tt::TokenId::unspecified()
438 }
439 fn with_span(&mut self, punct: Self::Punct, _span: Self::Span) -> Self::Punct {
440 // FIXME handle span
441 punct
442 }
443}
444
445impl server::Ident for Rustc {
446 fn new(&mut self, string: &str, _span: Self::Span, _is_raw: bool) -> Self::Ident {
447 IdentId(
448 self.ident_interner.intern(&IdentData(tt::Ident {
449 text: string.into(),
450 id: tt::TokenId::unspecified(),
451 })),
452 )
453 }
454
455 fn span(&mut self, _ident: Self::Ident) -> Self::Span {
456 // FIXME handle span
457 tt::TokenId::unspecified()
458 }
459 fn with_span(&mut self, ident: Self::Ident, _span: Self::Span) -> Self::Ident {
460 // FIXME handle span
461 ident
462 }
463}
464
465impl server::Literal for Rustc {
466 fn debug_kind(&mut self, _literal: &Self::Literal) -> String {
467 // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these.
468 // They must still be present to be ABI-compatible and work with upstream proc_macro.
469 "".to_owned()
470 }
471 fn symbol(&mut self, literal: &Self::Literal) -> String {
472 literal.text.to_string()
473 }
474 fn suffix(&mut self, _literal: &Self::Literal) -> Option<String> {
475 None
476 }
477
478 fn integer(&mut self, n: &str) -> Self::Literal {
479 let n: i128 = n.parse().unwrap();
480 Literal { text: n.to_string().into(), id: tt::TokenId::unspecified() }
481 }
482
483 fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
484 macro_rules! def_suffixed_integer {
485 ($kind:ident, $($ty:ty),*) => {
486 match $kind {
487 $(
488 stringify!($ty) => {
489 let n: $ty = n.parse().unwrap();
490 format!(concat!("{}", stringify!($ty)), n)
491 }
492 )*
493 _ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind),
494 }
495 }
496 }
497
498 let text =
499 def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128};
500
501 Literal { text: text.into(), id: tt::TokenId::unspecified() }
502 }
503
504 fn float(&mut self, n: &str) -> Self::Literal {
505 let n: f64 = n.parse().unwrap();
506 let mut text = f64::to_string(&n);
507 if !text.contains('.') {
508 text += ".0"
509 }
510 Literal { text: text.into(), id: tt::TokenId::unspecified() }
511 }
512
513 fn f32(&mut self, n: &str) -> Self::Literal {
514 let n: f32 = n.parse().unwrap();
515 let text = format!("{}f32", n);
516 Literal { text: text.into(), id: tt::TokenId::unspecified() }
517 }
518
519 fn f64(&mut self, n: &str) -> Self::Literal {
520 let n: f64 = n.parse().unwrap();
521 let text = format!("{}f64", n);
522 Literal { text: text.into(), id: tt::TokenId::unspecified() }
523 }
524
525 fn string(&mut self, string: &str) -> Self::Literal {
526 let mut escaped = String::new();
527 for ch in string.chars() {
528 escaped.extend(ch.escape_debug());
529 }
530 Literal { text: format!("\"{}\"", escaped).into(), id: tt::TokenId::unspecified() }
531 }
532
533 fn character(&mut self, ch: char) -> Self::Literal {
534 Literal { text: format!("'{}'", ch).into(), id: tt::TokenId::unspecified() }
535 }
536
537 fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
538 let string = bytes
539 .iter()
540 .cloned()
541 .flat_map(ascii::escape_default)
542 .map(Into::<char>::into)
543 .collect::<String>();
544
545 Literal { text: format!("b\"{}\"", string).into(), id: tt::TokenId::unspecified() }
546 }
547
548 fn span(&mut self, literal: &Self::Literal) -> Self::Span {
549 literal.id
550 }
551
552 fn set_span(&mut self, _literal: &mut Self::Literal, _span: Self::Span) {
553 // FIXME handle span
554 }
555
556 fn subspan(
557 &mut self,
558 _literal: &Self::Literal,
559 _start: Bound<usize>,
560 _end: Bound<usize>,
561 ) -> Option<Self::Span> {
562 // FIXME handle span
563 None
564 }
565}
566
567impl server::SourceFile for Rustc {
568 fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
569 file1.eq(file2)
570 }
571 fn path(&mut self, file: &Self::SourceFile) -> String {
572 String::from(
573 file.path().to_str().expect("non-UTF8 file path in `proc_macro::SourceFile::path`"),
574 )
575 }
576 fn is_real(&mut self, file: &Self::SourceFile) -> bool {
577 file.is_real()
578 }
579}
580
581impl server::Diagnostic for Rustc {
582 fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
583 let mut diag = Diagnostic::new(level, msg);
584 diag.spans = spans;
585 diag
586 }
587
588 fn sub(
589 &mut self,
590 _diag: &mut Self::Diagnostic,
591 _level: Level,
592 _msg: &str,
593 _spans: Self::MultiSpan,
594 ) {
595 // FIXME handle diagnostic
596 //
597 }
598
599 fn emit(&mut self, _diag: Self::Diagnostic) {
600 // FIXME handle diagnostic
601 // diag.emit()
602 }
603}
604
605impl server::Span for Rustc {
606 fn debug(&mut self, span: Self::Span) -> String {
607 format!("{:?}", span.0)
608 }
609 fn def_site(&mut self) -> Self::Span {
610 // MySpan(self.span_interner.intern(&MySpanData(Span::def_site())))
611 // FIXME handle span
612 tt::TokenId::unspecified()
613 }
614 fn call_site(&mut self) -> Self::Span {
615 // MySpan(self.span_interner.intern(&MySpanData(Span::call_site())))
616 // FIXME handle span
617 tt::TokenId::unspecified()
618 }
619 fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
620 // let MySpanData(span) = self.span_interner.get(span.0);
621 unimplemented!()
622 }
623
624 /// Recent feature, not yet in the proc_macro
625 ///
626 /// See PR:
627 /// https://github.com/rust-lang/rust/pull/55780
628 fn source_text(&mut self, _span: Self::Span) -> Option<String> {
629 None
630 }
631
632 fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
633 // FIXME handle span
634 None
635 }
636 fn source(&mut self, span: Self::Span) -> Self::Span {
637 // FIXME handle span
638 span
639 }
640 fn start(&mut self, _span: Self::Span) -> LineColumn {
641 // FIXME handle span
642 LineColumn { line: 0, column: 0 }
643 }
644 fn end(&mut self, _span: Self::Span) -> LineColumn {
645 // FIXME handle span
646 LineColumn { line: 0, column: 0 }
647 }
648 fn join(&mut self, _first: Self::Span, _second: Self::Span) -> Option<Self::Span> {
649 None
650 }
651 fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span {
652 // FIXME handle span
653 tt::TokenId::unspecified()
654 }
655
656 fn mixed_site(&mut self) -> Self::Span {
657 // FIXME handle span
658 tt::TokenId::unspecified()
659 }
660}
661
662impl server::MultiSpan for Rustc {
663 fn new(&mut self) -> Self::MultiSpan {
664 // FIXME handle span
665 vec![]
666 }
667
668 fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) {
669 //TODP
670 other.push(span)
671 }
672}
673
674#[cfg(test)]
675mod tests {
676 use super::*;
677 use crate::proc_macro::bridge::server::Literal;
678
679 #[test]
680 fn test_rustc_server_literals() {
681 let mut srv = Rustc { ident_interner: IdentInterner::default() };
682 assert_eq!(srv.integer("1234").text, "1234");
683
684 assert_eq!(srv.typed_integer("12", "u8").text, "12u8");
685 assert_eq!(srv.typed_integer("255", "u16").text, "255u16");
686 assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32");
687 assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64");
688 assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128");
689 assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize");
690 assert_eq!(srv.typed_integer("127", "i8").text, "127i8");
691 assert_eq!(srv.typed_integer("255", "i16").text, "255i16");
692 assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32");
693 assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64");
694 assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128");
695 assert_eq!(srv.float("0").text, "0.0");
696 assert_eq!(srv.float("15684.5867").text, "15684.5867");
697 assert_eq!(srv.f32("15684.58").text, "15684.58f32");
698 assert_eq!(srv.f64("15684.58").text, "15684.58f64");
699
700 assert_eq!(srv.string("hello_world").text, "\"hello_world\"");
701 assert_eq!(srv.character('c').text, "'c'");
702 assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\"");
703 }
704}