From c0a5e2202d0a7e0f945b6d90d7ec648bc75a9f60 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sat, 2 Sep 2023 13:58:45 -0400 Subject: [PATCH] lazy utf-8 validation Makes text::Reader a wrapper around &[u8] and defers utf-8 validation until `to_str()` or `to_string()` is called. This means that users will only need to pay the utf8 validation cost if they actually need it. This also allows users to access (broken) non-utf8 Text data. Previously such data was inaccessible. --- benchmark/carsales.rs | 4 +- benchmark/catrank.rs | 4 +- capnp-futures/test/test.rs | 16 +- capnp-rpc/examples/hello-world/client.rs | 7 +- capnp-rpc/examples/hello-world/server.rs | 4 +- capnp-rpc/examples/pubsub/client.rs | 2 +- capnp-rpc/examples/pubsub/server.rs | 5 +- capnp-rpc/src/rpc.rs | 10 +- capnp-rpc/test/impls.rs | 12 +- capnp-rpc/test/reconnect_test.rs | 4 +- capnp-rpc/test/test_util.rs | 28 +-- capnp/src/private/layout.rs | 28 +-- capnp/src/stringify.rs | 12 +- capnp/src/text.rs | 190 +++++++++++++++---- capnpc/src/codegen.rs | 40 ++-- capnpc/src/codegen_types.rs | 6 +- capnpc/test/dynamic.rs | 8 +- capnpc/test/test.rs | 87 +++++---- capnpc/test/test_util.rs | 52 +++-- example/addressbook/addressbook.rs | 28 +-- example/addressbook_send/addressbook_send.rs | 16 +- 21 files changed, 361 insertions(+), 202 deletions(-) diff --git a/benchmark/carsales.rs b/benchmark/carsales.rs index 9942ad10e..0c1769aff 100644 --- a/benchmark/carsales.rs +++ b/benchmark/carsales.rs @@ -82,8 +82,8 @@ const MAKES: [&str; 5] = ["Toyota", "GM", "Ford", "Honda", "Tesla"]; const MODELS: [&str; 6] = ["Camry", "Prius", "Volt", "Accord", "Leaf", "Model S"]; pub fn random_car(rng: &mut FastRand, mut car: car::Builder) { - car.set_make(MAKES[rng.next_less_than(MAKES.len() as u32) as usize]); - car.set_model(MODELS[rng.next_less_than(MODELS.len() as u32) as usize]); + car.set_make(MAKES[rng.next_less_than(MAKES.len() as u32) as usize].into()); + car.set_model(MODELS[rng.next_less_than(MODELS.len() as u32) as usize].into()); car.set_color( (rng.next_less_than(Color::Silver as u32 + 1) as u16) diff --git a/benchmark/catrank.rs b/benchmark/catrank.rs index 0f606671b..176e99011 100644 --- a/benchmark/catrank.rs +++ b/benchmark/catrank.rs @@ -84,7 +84,7 @@ impl crate::TestCase for CatRank { snippet.push_str(WORDS[rng.next_less_than(WORDS.len() as u32) as usize]); } - result.set_snippet(&snippet); + result.set_snippet(snippet[..].into()); } good_count @@ -101,7 +101,7 @@ impl crate::TestCase for CatRank { for i in 0..results.len() { let result = results.get(i); let mut score = result.get_score(); - let snippet = result.get_snippet()?; + let snippet = result.get_snippet()?.to_str()?; if snippet.contains(" cat ") { score *= 10000.0; } diff --git a/capnp-futures/test/test.rs b/capnp-futures/test/test.rs index 557069999..45a8b5c35 100644 --- a/capnp-futures/test/test.rs +++ b/capnp-futures/test/test.rs @@ -35,32 +35,32 @@ mod tests { { let mut alice = people.reborrow().get(0); alice.set_id(123); - alice.set_name("Alice"); - alice.set_email("alice@example.com"); + alice.set_name("Alice".into()); + alice.set_email("alice@example.com".into()); { let mut alice_phones = alice.reborrow().init_phones(1); - alice_phones.reborrow().get(0).set_number("555-1212"); + alice_phones.reborrow().get(0).set_number("555-1212".into()); alice_phones .reborrow() .get(0) .set_type(person::phone_number::Type::Mobile); } - alice.get_employment().set_school("MIT"); + alice.get_employment().set_school("MIT".into()); } { let mut bob = people.get(1); bob.set_id(456); - bob.set_name("Bob"); - bob.set_email("bob@example.com"); + bob.set_name("Bob".into()); + bob.set_email("bob@example.com".into()); { let mut bob_phones = bob.reborrow().init_phones(2); - bob_phones.reborrow().get(0).set_number("555-4567"); + bob_phones.reborrow().get(0).set_number("555-4567".into()); bob_phones .reborrow() .get(0) .set_type(person::phone_number::Type::Home); - bob_phones.reborrow().get(1).set_number("555-7654"); + bob_phones.reborrow().get(1).set_number("555-7654".into()); bob_phones .reborrow() .get(1) diff --git a/capnp-rpc/examples/hello-world/client.rs b/capnp-rpc/examples/hello-world/client.rs index 865d96748..af59b3d73 100644 --- a/capnp-rpc/examples/hello-world/client.rs +++ b/capnp-rpc/examples/hello-world/client.rs @@ -58,11 +58,14 @@ pub async fn main() -> Result<(), Box> { tokio::task::spawn_local(rpc_system); let mut request = hello_world.say_hello_request(); - request.get().init_request().set_name(&msg); + request.get().init_request().set_name(msg[..].into()); let reply = request.send().promise.await?; - println!("received: {}", reply.get()?.get_reply()?.get_message()?); + println!( + "received: {}", + reply.get()?.get_reply()?.get_message()?.to_str()? + ); Ok(()) }) .await diff --git a/capnp-rpc/examples/hello-world/server.rs b/capnp-rpc/examples/hello-world/server.rs index e88a18496..f2ea14e8f 100644 --- a/capnp-rpc/examples/hello-world/server.rs +++ b/capnp-rpc/examples/hello-world/server.rs @@ -36,10 +36,10 @@ impl hello_world::Server for HelloWorldImpl { mut results: hello_world::SayHelloResults, ) -> Promise<(), ::capnp::Error> { let request = pry!(pry!(params.get()).get_request()); - let name = pry!(request.get_name()); + let name = pry!(pry!(request.get_name()).to_str()); let message = format!("Hello, {name}!"); - results.get().init_reply().set_message(&message); + results.get().init_reply().set_message(message[..].into()); Promise::ok(()) } diff --git a/capnp-rpc/examples/pubsub/client.rs b/capnp-rpc/examples/pubsub/client.rs index ae78fe3cf..9ad0da313 100644 --- a/capnp-rpc/examples/pubsub/client.rs +++ b/capnp-rpc/examples/pubsub/client.rs @@ -35,7 +35,7 @@ impl subscriber::Server<::capnp::text::Owned> for SubscriberImpl { ) -> Promise<(), ::capnp::Error> { println!( "message from publisher: {}", - pry!(pry!(params.get()).get_message()) + pry!(pry!(pry!(params.get()).get_message()).to_str()) ); Promise::ok(()) } diff --git a/capnp-rpc/examples/pubsub/server.rs b/capnp-rpc/examples/pubsub/server.rs index cb3a1fe08..8563caf90 100644 --- a/capnp-rpc/examples/pubsub/server.rs +++ b/capnp-rpc/examples/pubsub/server.rs @@ -167,7 +167,10 @@ pub async fn main() -> Result<(), Box> { subscriber.requests_in_flight += 1; let mut request = subscriber.client.push_message_request(); request.get().set_message( - &format!("system time is: {:?}", ::std::time::SystemTime::now())[..])?; + (&format!("system time is: {:?}", ::std::time::SystemTime::now()) + [..]) + .into(), + )?; let subscribers2 = subscribers1.clone(); tokio::task::spawn_local(request.send().promise.map( move |r| match r { diff --git a/capnp-rpc/src/rpc.rs b/capnp-rpc/src/rpc.rs index fb3363493..808e75e01 100644 --- a/capnp-rpc/src/rpc.rs +++ b/capnp-rpc/src/rpc.rs @@ -355,7 +355,7 @@ fn to_pipeline_ops( } fn from_error(error: &Error, mut builder: exception::Builder) { - builder.set_reason(&error.to_string()); + builder.set_reason(error.to_string()[..].into()); let typ = match error.kind { ::capnp::ErrorKind::Failed => exception::Type::Failed, ::capnp::ErrorKind::Overloaded => exception::Type::Overloaded, @@ -379,10 +379,14 @@ fn remote_exception_to_error(exception: exception::Reader) -> Error { (Ok(exception::Type::Unimplemented), Ok(reason)) => { (::capnp::ErrorKind::Unimplemented, reason) } - _ => (::capnp::ErrorKind::Failed, "(malformed error)"), + _ => (::capnp::ErrorKind::Failed, "(malformed error)".into()), + }; + let reason_str = match reason.to_str() { + Ok(s) => s, + Err(_) => "", }; Error { - extra: format!("remote exception: {reason}"), + extra: format!("remote exception: {reason_str}"), kind, } } diff --git a/capnp-rpc/test/impls.rs b/capnp-rpc/test/impls.rs index d79f81260..71571bb50 100644 --- a/capnp-rpc/test/impls.rs +++ b/capnp-rpc/test/impls.rs @@ -148,7 +148,7 @@ impl test_interface::Server for TestInterface { } { let mut results = results.get(); - results.set_x("foo"); + results.set_x("foo".into()); } Promise::ok(()) } @@ -190,7 +190,7 @@ impl test_interface::Server for TestExtends { } { let mut results = results.get(); - results.set_x("bar"); + results.set_x("bar".into()); } Promise::ok(()) } @@ -259,7 +259,7 @@ impl test_pipeline::Server for TestPipeline { return Err(Error::failed("expected x to equal 'foo'".to_string())); } - results.get().set_s("bar"); + results.get().set_s("bar".into()); // TODO implement better casting results @@ -352,7 +352,7 @@ impl test_more_stuff::Server for TestMoreStuff { if response?.get()?.get_x()? != "foo" { return Err(Error::failed("expected x to equal 'foo'".to_string())); } - results.get().set_s("bar"); + results.get().set_s("bar".into()); Ok(()) })) } @@ -372,7 +372,7 @@ impl test_more_stuff::Server for TestMoreStuff { if response?.get()?.get_x()? != "foo" { return Err(Error::failed("expected x to equal 'foo'".to_string())); } - results.get().set_s("bar"); + results.get().set_s("bar".into()); Ok(()) }) })) @@ -438,7 +438,7 @@ impl test_more_stuff::Server for TestMoreStuff { if response?.get()?.get_x()? != "foo" { Err(Error::failed("expected X to equal 'foo'".to_string())) } else { - results.get().set_s("bar"); + results.get().set_s("bar".into()); Ok(()) } })) diff --git a/capnp-rpc/test/reconnect_test.rs b/capnp-rpc/test/reconnect_test.rs index c327b7a2b..f29a203e5 100644 --- a/capnp-rpc/test/reconnect_test.rs +++ b/capnp-rpc/test/reconnect_test.rs @@ -76,7 +76,7 @@ impl test_interface::Server for TestInterfaceImpl { ); { let mut results = results.get(); - results.set_x(&s); + results.set_x(s[..].into()); } if let Some(fut) = self.inner.borrow().block.as_ref() { Promise::from_future(fut.clone()) @@ -91,7 +91,7 @@ where F: Future>>, { match pool.run_until(fut) { - Ok(resp) => Ok(resp.get()?.get_x()?.to_string()), + Ok(resp) => Ok(resp.get()?.get_x()?.to_string()?), Err(err) => Err(err), } } diff --git a/capnp-rpc/test/test_util.rs b/capnp-rpc/test/test_util.rs index eaeb3f883..f06a54717 100644 --- a/capnp-rpc/test/test_util.rs +++ b/capnp-rpc/test/test_util.rs @@ -34,7 +34,7 @@ pub fn init_test_message(mut builder: test_all_types::Builder) { builder.set_u_int64_field(12345678901234567890); builder.set_float32_field(1234.5); builder.set_float64_field(-123e45); - builder.set_text_field("foo"); + builder.set_text_field("foo".into()); builder.set_data_field(b"bar"); { let mut sub_builder = builder.reborrow().init_struct_field(); @@ -50,14 +50,14 @@ pub fn init_test_message(mut builder: test_all_types::Builder) { sub_builder.set_u_int64_field(345678901234567890); sub_builder.set_float32_field(-1.25e-10); sub_builder.set_float64_field(345f64); - sub_builder.set_text_field("baz"); + sub_builder.set_text_field("baz".into()); sub_builder.set_data_field(b"qux"); { let mut sub_sub_builder = sub_builder.reborrow().init_struct_field(); - sub_sub_builder.set_text_field("nested"); + sub_sub_builder.set_text_field("nested".into()); sub_sub_builder .init_struct_field() - .set_text_field("really nested"); + .set_text_field("really nested".into()); } sub_builder.set_enum_field(TestEnum::Baz); @@ -105,15 +105,15 @@ pub fn init_test_message(mut builder: test_all_types::Builder) { struct_list .reborrow() .get(0) - .set_text_field("x structlist 1"); + .set_text_field("x structlist 1".into()); struct_list .reborrow() .get(1) - .set_text_field("x structlist 2"); + .set_text_field("x structlist 2".into()); struct_list .reborrow() .get(2) - .set_text_field("x structlist 3"); + .set_text_field("x structlist 3".into()); } let mut enum_list = sub_builder.reborrow().init_enum_list(3); @@ -149,7 +149,7 @@ check_test_message_impl(($typ:ident) => ( assert_eq!(12345678901234567890, reader.reborrow().get_u_int64_field()); assert_eq!(1234.5, reader.reborrow().get_float32_field()); assert_eq!(-123e45, reader.reborrow().get_float64_field()); - assert_eq!("foo", &*reader.reborrow().get_text_field().unwrap()); + assert_eq!("foo", reader.reborrow().get_text_field().unwrap()); assert_eq!(b"bar", &*reader.reborrow().get_data_field().unwrap()); { let mut sub_reader = reader.get_struct_field().unwrap(); @@ -165,12 +165,12 @@ check_test_message_impl(($typ:ident) => ( assert_eq!(345678901234567890, sub_reader.reborrow().get_u_int64_field()); assert_eq!(-1.25e-10, sub_reader.reborrow().get_float32_field()); assert_eq!(345f64, sub_reader.reborrow().get_float64_field()); - assert_eq!("baz", &*sub_reader.reborrow().get_text_field().unwrap()); + assert_eq!("baz", sub_reader.reborrow().get_text_field().unwrap()); assert_eq!(b"qux", &*sub_reader.reborrow().get_data_field().unwrap()); { let mut sub_sub_reader = sub_reader.reborrow().get_struct_field().unwrap(); - assert_eq!("nested", &*sub_sub_reader.reborrow().get_text_field().unwrap()); - assert_eq!("really nested", &*sub_sub_reader.get_struct_field().unwrap() + assert_eq!("nested", sub_sub_reader.reborrow().get_text_field().unwrap()); + assert_eq!("really nested", sub_sub_reader.get_struct_field().unwrap() .get_text_field().unwrap()); } assert!(Ok(TestEnum::Baz) == sub_reader.reborrow().get_enum_field()); @@ -218,9 +218,9 @@ check_test_message_impl(($typ:ident) => ( { let mut struct_list = sub_reader.reborrow().get_struct_list().unwrap(); assert_eq!(3, struct_list.len()); - assert_eq!("x structlist 1", &*struct_list.reborrow().get(0).get_text_field().unwrap()); - assert_eq!("x structlist 2", &*struct_list.reborrow().get(1).get_text_field().unwrap()); - assert_eq!("x structlist 3", &*struct_list.reborrow().get(2).get_text_field().unwrap()); + assert_eq!("x structlist 1", struct_list.reborrow().get(0).get_text_field().unwrap()); + assert_eq!("x structlist 2", struct_list.reborrow().get(1).get_text_field().unwrap()); + assert_eq!("x structlist 3", struct_list.reborrow().get(2).get_text_field().unwrap()); } { diff --git a/capnp/src/private/layout.rs b/capnp/src/private/layout.rs index f52147f80..076e34de9 100644 --- a/capnp/src/private/layout.rs +++ b/capnp/src/private/layout.rs @@ -1730,8 +1730,7 @@ mod wire_helpers { SegmentAnd { segment_id, - value: text::Builder::new(slice::from_raw_parts_mut(ptr, size as usize), 0) - .expect("empty text builder should be valid utf-8"), + value: text::Builder::new(slice::from_raw_parts_mut(ptr, size as usize)), } } @@ -1740,12 +1739,16 @@ mod wire_helpers { arena: &'a mut dyn BuilderArena, reff: *mut WirePointer, segment_id: u32, - value: &str, + value: crate::text::Reader<'_>, ) -> SegmentAnd> { let value_bytes = value.as_bytes(); // TODO make sure the string is not longer than 2 ** 29. let mut allocation = init_text_pointer(arena, reff, segment_id, value_bytes.len() as u32); - allocation.value.push_str(value); + allocation + .value + .reborrow() + .as_bytes_mut() + .copy_from_slice(value_bytes); allocation } @@ -1758,7 +1761,7 @@ mod wire_helpers { ) -> Result> { let ref_target = if (*reff).is_null() { match default { - None => return text::Builder::new(&mut [], 0), + None => return Ok(text::Builder::new(&mut [])), Some(d) => { let (new_ref_target, new_reff, new_segment_id) = copy_message( arena, @@ -1793,10 +1796,10 @@ mod wire_helpers { } // Subtract 1 from the size for the NUL terminator. - text::Builder::new( + Ok(text::Builder::with_pos( slice::from_raw_parts_mut(ptr, (count - 1) as usize), - count - 1, - ) + (count - 1) as usize, + )) } #[inline] @@ -2615,7 +2618,7 @@ mod wire_helpers { ) -> Result> { if (*reff).is_null() { match default { - None => return Ok(""), + None => return Ok("".into()), Some(d) => { reff = d.as_ptr() as *const WirePointer; arena = &super::NULL_ARENA; @@ -2661,7 +2664,10 @@ mod wire_helpers { )); } - text::new_reader(slice::from_raw_parts(str_ptr, size as usize - 1)) + Ok(text::Reader(slice::from_raw_parts( + str_ptr, + size as usize - 1, + ))) } #[inline] @@ -3282,7 +3288,7 @@ impl<'a> PointerBuilder<'a> { } } - pub fn set_text(&mut self, value: &str) { + pub fn set_text(&mut self, value: crate::text::Reader<'_>) { unsafe { wire_helpers::set_text_pointer(self.arena, self.pointer, self.segment_id, value); } diff --git a/capnp/src/stringify.rs b/capnp/src/stringify.rs index a7bb8a7a4..d11bfbeb7 100644 --- a/capnp/src/stringify.rs +++ b/capnp/src/stringify.rs @@ -46,7 +46,7 @@ impl Indent { } } -fn cvt(r: crate::Result) -> Result { +fn cvt(r: core::result::Result) -> Result { match r { Ok(v) => Ok(v), Err(_) => Err(fmt::Error), @@ -72,7 +72,9 @@ pub(crate) fn print( dynamic_value::Reader::Float32(x) => formatter.write_fmt(format_args!("{x}")), dynamic_value::Reader::Float64(x) => formatter.write_fmt(format_args!("{x}")), dynamic_value::Reader::Enum(e) => match cvt(e.get_enumerant())? { - Some(enumerant) => formatter.write_str(cvt(enumerant.get_proto().get_name())?), + Some(enumerant) => { + formatter.write_str(cvt(cvt(enumerant.get_proto().get_name())?.to_str())?) + } None => formatter.write_fmt(format_args!("{}", e.get_value())), }, dynamic_value::Reader::Text(t) => formatter.write_fmt(format_args!("{t:?}")), @@ -131,7 +133,7 @@ pub(crate) fn print( indent2.comma(formatter)?; } indent2.maybe_newline(formatter)?; - formatter.write_str(cvt(ff.get_proto().get_name())?)?; + formatter.write_str(cvt(cvt(ff.get_proto().get_name())?.to_str())?)?; formatter.write_str(" = ")?; print(cvt(st.get(ff))?, formatter, indent2)?; union_field = None; @@ -144,7 +146,7 @@ pub(crate) fn print( indent2.comma(formatter)?; } indent2.maybe_newline(formatter)?; - formatter.write_str(cvt(field.get_proto().get_name())?)?; + formatter.write_str(cvt(cvt(field.get_proto().get_name())?.to_str())?)?; formatter.write_str(" = ")?; print(cvt(st.get(field))?, formatter, indent2)?; } @@ -155,7 +157,7 @@ pub(crate) fn print( indent2.comma(formatter)?; } indent2.maybe_newline(formatter)?; - formatter.write_str(cvt(ff.get_proto().get_name())?)?; + formatter.write_str(cvt(cvt(ff.get_proto().get_name())?.to_str())?)?; formatter.write_str(" = ")?; print(cvt(st.get(ff))?, formatter, indent2)?; } diff --git a/capnp/src/text.rs b/capnp/src/text.rs index 50344d7b9..e730bb804 100644 --- a/capnp/src/text.rs +++ b/capnp/src/text.rs @@ -21,9 +21,9 @@ //! UTF-8 encoded text. -use core::{convert, ops, str}; +use core::str; -use crate::{Error, ErrorKind, Result}; +use crate::Result; #[derive(Copy, Clone)] pub struct Owned(()); @@ -39,12 +39,56 @@ impl crate::introspect::Introspect for Owned { } } -pub type Reader<'a> = &'a str; +/// Wrapper around utf-8 encoded text. +/// This is defined as a tuple struct to allow pattern matching +/// on it via byte literals (for example `text::Reader(b"hello")`). +#[derive(Copy, Clone, PartialEq)] +pub struct Reader<'a>(pub &'a [u8]); -pub fn new_reader(v: &[u8]) -> Result> { - match str::from_utf8(v) { - Ok(v) => Ok(v), - Err(e) => Err(Error::from_kind(ErrorKind::TextContainsNonUtf8Data(e))), +impl<'a> core::cmp::PartialEq<&'a str> for Reader<'a> { + fn eq(&self, other: &&'a str) -> bool { + self.as_bytes() == other.as_bytes() + } +} + +impl<'a> core::cmp::PartialEq> for &'a str { + fn eq(&self, other: &Reader<'a>) -> bool { + self.as_bytes() == other.as_bytes() + } +} + +impl<'a> core::fmt::Debug for Reader<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.to_str() { + Ok(s) => write!(f, "{:?}", s), + Err(_) => write!(f, "", self.as_bytes()), + } + } +} + +impl<'a> From<&'a str> for Reader<'a> { + fn from(value: &'a str) -> Self { + Self(value.as_bytes()) + } +} + +impl<'a> From<&'a [u8]> for Reader<'a> { + fn from(value: &'a [u8]) -> Self { + Self(value) + } +} + +impl<'a, const N: usize> From<&'a [u8; N]> for Reader<'a> { + fn from(value: &'a [u8; N]) -> Self { + Self(&value[..]) + } +} + +impl<'a> TryFrom> for &'a str { + type Error = core::str::Utf8Error; + fn try_from(value: Reader<'a>) -> core::result::Result<&'a str, core::str::Utf8Error> { + let Reader(v) = value; + str::from_utf8(v) } } @@ -57,36 +101,102 @@ impl<'a> crate::traits::FromPointerReader<'a> for Reader<'a> { } } +impl<'a> Reader<'a> { + pub fn len(&self) -> usize { + self.as_bytes().len() + } + + pub fn as_bytes(self) -> &'a [u8] { + let Self(d) = self; + d + } + + /// Converts to a `str`, returning a error if the data contains invalid utf-8. + pub fn to_str(self) -> core::result::Result<&'a str, core::str::Utf8Error> { + let Self(s) = self; + str::from_utf8(s) + } + + #[cfg(feature = "alloc")] + /// Converts to a `String`, returning a error if the data contains invalid utf-8. + pub fn to_string(self) -> core::result::Result { + Ok(self.to_str()?.into()) + } +} + pub struct Builder<'a> { + /// Does not include the trailing null byte. bytes: &'a mut [u8], + + /// Position at which `push_ascii()` and `push_str()` will write to. pos: usize, } +impl<'a> core::cmp::PartialEq for Builder<'a> { + fn eq(&self, other: &Self) -> bool { + self.bytes == other.bytes + } +} + +impl<'a> core::cmp::PartialEq<&'a str> for Builder<'a> { + fn eq(&self, other: &&'a str) -> bool { + self.bytes == other.as_bytes() + } +} + +impl<'a> core::cmp::PartialEq> for &'a str { + fn eq(&self, other: &Builder<'a>) -> bool { + self.as_bytes() == other.bytes + } +} + impl<'a> Builder<'a> { - pub fn new(bytes: &mut [u8], pos: u32) -> Result> { - if pos != 0 { - if let Err(e) = str::from_utf8(bytes) { - return Err(Error::from_kind(ErrorKind::TextContainsNonUtf8Data(e))); - } - } - Ok(Builder { - bytes, - pos: pos as usize, - }) + pub fn new(bytes: &mut [u8]) -> Builder<'_> { + Builder { bytes, pos: 0 } + } + + pub fn with_pos(bytes: &mut [u8], pos: usize) -> Builder<'_> { + Builder { bytes, pos } + } + + pub fn len(&self) -> usize { + self.bytes.len() + } + + pub fn as_bytes(self) -> &'a [u8] { + &self.bytes[..] + } + + /// Converts to a `str`, returning a error if the data contains invalid utf-8. + pub fn to_str(self) -> core::result::Result<&'a str, core::str::Utf8Error> { + str::from_utf8(&self.bytes[..]) + } + + #[cfg(feature = "alloc")] + /// Converts to a `String`, returning a error if the data contains invalid utf-8. + pub fn to_string(self) -> core::result::Result { + Ok(self.to_str()?.into()) + } + + pub fn as_bytes_mut(self) -> &'a mut [u8] { + &mut self.bytes[..] } + /// Writes a single ascii character at position `pos` and increments `pos`. pub fn push_ascii(&mut self, ascii: u8) { assert!(ascii < 128); self.bytes[self.pos] = ascii; self.pos += 1; } + /// Writes a string at position `pos` and increases `pos` a corresponding amount. pub fn push_str(&mut self, string: &str) { let bytes = string.as_bytes(); self.bytes[self.pos..(self.pos + bytes.len())].copy_from_slice(bytes); self.pos += bytes.len(); } + /// Zeroes all data and resets `pos`. pub fn clear(&mut self) { for b in &mut self.bytes[..self.pos] { *b = 0; @@ -102,29 +212,20 @@ impl<'a> Builder<'a> { } pub fn into_reader(self) -> Reader<'a> { - str::from_utf8(self.bytes).unwrap() + Reader(self.bytes) } -} - -impl<'a> ops::Deref for Builder<'a> { - type Target = str; - fn deref(&self) -> &str { - str::from_utf8(self.bytes) - .expect("text::Builder contents are checked for utf8-validity upon construction") - } -} -impl<'a> ops::DerefMut for Builder<'a> { - fn deref_mut(&mut self) -> &mut str { - str::from_utf8_mut(self.bytes) - .expect("text::Builder contents are checked for utf8-validity upon construction") + pub fn reborrow_as_reader(&self) -> Reader<'_> { + Reader(&self.bytes[..]) } } -impl<'a> convert::AsRef for Builder<'a> { - fn as_ref(&self) -> &str { - str::from_utf8(self.bytes) - .expect("text::Builder contents are checked for utf8-validity upon construction") +impl<'a> core::fmt::Debug for Builder<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.reborrow_as_reader().to_str() { + Ok(s) => write!(f, "{:?}", s), + Err(_) => write!(f, ""), + } } } @@ -151,12 +252,31 @@ impl<'a> crate::traits::SetPointerBuilder for Reader<'a> { } } +// Extra impl to make any_pointer::Builder::set_as() and similar methods work +// more smoothly. +impl<'a> crate::traits::SetPointerBuilder for &'a str { + fn set_pointer_builder<'b>( + mut pointer: crate::private::layout::PointerBuilder<'b>, + value: &'a str, + _canonicalize: bool, + ) -> Result<()> { + pointer.set_text(value.into()); + Ok(()) + } +} + impl<'a> From> for crate::dynamic_value::Reader<'a> { fn from(t: Reader<'a>) -> crate::dynamic_value::Reader<'a> { crate::dynamic_value::Reader::Text(t) } } +impl<'a> From<&'a str> for crate::dynamic_value::Reader<'a> { + fn from(t: &'a str) -> crate::dynamic_value::Reader<'a> { + crate::dynamic_value::Reader::Text(t.into()) + } +} + impl<'a> From> for crate::dynamic_value::Builder<'a> { fn from(t: Builder<'a>) -> crate::dynamic_value::Builder<'a> { crate::dynamic_value::Builder::Text(t) diff --git a/capnpc/src/codegen.rs b/capnpc/src/codegen.rs index 7cd7ef89c..9449718eb 100644 --- a/capnpc/src/codegen.rs +++ b/capnpc/src/codegen.rs @@ -123,7 +123,7 @@ impl CodeGenerationCommand { for requested_file in ctx.request.get_requested_files()? { let id = requested_file.get_id(); let mut filepath = self.output_directory.to_path_buf(); - let requested = ::std::path::PathBuf::from(requested_file.get_filename()?); + let requested = ::std::path::PathBuf::from(requested_file.get_filename()?.to_str()?); filepath.push(requested); if let Some(parent) = filepath.parent() { ::std::fs::create_dir_all(parent).map_err(convert_io_err)?; @@ -132,13 +132,14 @@ impl CodeGenerationCommand { let root_name = path_to_stem_string(&filepath)?.replace('-', "_"); filepath.set_file_name(&format!("{root_name}_capnp.rs")); - let lines = Branch(vec![ + let lines = + Branch(vec![ Line( "// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler." .to_string(), ), line("// DO NOT EDIT."), - Line(format!("// source: {}", requested_file.get_filename()?)), + Line(format!("// source: {}", requested_file.get_filename()?.to_str()?)), BlankLine, generate_node(&ctx, id, &root_name)?, ]); @@ -247,7 +248,7 @@ impl<'a> GeneratorContext<'a> { let id = requested_file.get_id(); for import in requested_file.get_imports()? { - let importpath = ::std::path::Path::new(import.get_name()?); + let importpath = ::std::path::Path::new(import.get_name()?.to_str()?); let root_name: String = format!( "{}_capnp", path_to_stem_string(importpath)?.replace('-', "_") @@ -267,7 +268,7 @@ impl<'a> GeneratorContext<'a> { )?; } - let root_name = path_to_stem_string(requested_file.get_filename()?)?; + let root_name = path_to_stem_string(requested_file.get_filename()?.to_str()?)?; let root_mod = format!("{}_capnp", root_name.replace('-', "_")); ctx.populate_scope_map( default_parent_module_scope.clone(), @@ -329,7 +330,7 @@ impl<'a> GeneratorContext<'a> { Ok(schema_capnp::node::Enum(_enum_reader)) => { self.populate_scope_map( scope_names.clone(), - nested_node.get_name()?.to_string(), + nested_node.get_name()?.to_string()?, NameKind::Verbatim, nested_node_id, )?; @@ -337,7 +338,7 @@ impl<'a> GeneratorContext<'a> { _ => { self.populate_scope_map( scope_names.clone(), - nested_node.get_name()?.to_string(), + nested_node.get_name()?.to_string()?, NameKind::Module, nested_node_id, )?; @@ -530,7 +531,7 @@ const OPTION_ANNOTATION_ID: u64 = 0xabfef22c4ee1964e; fn name_annotation_value(annotation: schema_capnp::annotation::Reader) -> capnp::Result<&str> { if let schema_capnp::value::Text(t) = annotation.get_value()?.which()? { - let name = t?; + let name = t?.to_str()?; for c in name.chars() { if !(c == '_' || c.is_alphanumeric()) { return Err(capnp::Error::failed( @@ -553,7 +554,7 @@ fn get_field_name(field: schema_capnp::field::Reader) -> capnp::Result<&str> { return name_annotation_value(annotation); } } - field.get_name() + Ok(field.get_name()?.to_str()?) } fn get_enumerant_name(enumerant: schema_capnp::enumerant::Reader) -> capnp::Result<&str> { @@ -562,12 +563,12 @@ fn get_enumerant_name(enumerant: schema_capnp::enumerant::Reader) -> capnp::Resu return name_annotation_value(annotation); } } - enumerant.get_name() + Ok(enumerant.get_name()?.to_str()?) } fn get_parent_module(annotation: schema_capnp::annotation::Reader) -> capnp::Result> { if let schema_capnp::value::Text(t) = annotation.get_value()?.which()? { - let module = t?; + let module = t?.to_str()?; Ok(module.split("::").map(|x| x.to_string()).collect()) } else { Err(capnp::Error::failed( @@ -662,7 +663,7 @@ fn get_params(ctx: &GeneratorContext, mut node_id: u64) -> ::capnp::Result match scope.which()? { brand::scope::Inherit(()) => { for param in params { - used_params.insert(param.get_name()?.to_string()); + used_params.insert(param.get_name()?.to_string()?); } } brand::scope::Bind(bindings_list_opt) => { @@ -1856,7 +1857,7 @@ fn get_ty_params_of_brand( for (scope_id, parameter_index) in acc.into_iter() { let node = ctx.node_map[&scope_id]; let p = node.get_parameters()?.get(u32::from(parameter_index)); - result.push_str(p.get_name()?); + result.push_str(p.get_name()?.to_str()?); result.push(','); } @@ -2496,7 +2497,7 @@ fn generate_node( let methods = interface.get_methods()?; for (ordinal, method) in methods.into_iter().enumerate() { - let name = method.get_name()?; + let name = method.get_name()?.to_str()?; let param_id = method.get_param_struct_type(); let param_node = &ctx.node_map[¶m_id]; @@ -2928,9 +2929,10 @@ fn generate_node( } } - (type_::Text(()), value::Text(t)) => { - Line(format!("pub const {styled_name}: &str = {:?};", t?)) - } + (type_::Text(()), value::Text(t)) => Line(format!( + "pub const {styled_name}: &str = {:?};", + t?.to_str()? + )), (type_::Data(()), value::Data(d)) => { Line(format!("pub const {styled_name}: &[u8] = &{:?};", d?)) } diff --git a/capnpc/src/codegen_types.rs b/capnpc/src/codegen_types.rs index a8790fa4e..54a201e7a 100644 --- a/capnpc/src/codegen_types.rs +++ b/capnpc/src/codegen_types.rs @@ -259,7 +259,7 @@ impl<'a> RustTypeInfo for type_::Reader<'a> { let the_struct = &ctx.node_map[&def.get_scope_id()]; let parameters = the_struct.get_parameters()?; let parameter = parameters.get(u32::from(def.get_parameter_index())); - let parameter_name = parameter.get_name()?; + let parameter_name = parameter.get_name()?.to_str()?; match module { Leaf::Owned => Ok(parameter_name.to_string()), Leaf::Reader(lifetime) => Ok(fmt!( @@ -376,7 +376,7 @@ pub fn do_branding( Some(scope) => match scope.which()? { brand::scope::Inherit(()) => { for param in params { - arguments.push(param.get_name()?.to_string()); + arguments.push(param.get_name()?.to_string()?); } } brand::scope::Bind(bindings_list_opt) => { @@ -437,7 +437,7 @@ pub fn get_type_parameters(ctx: &GeneratorContext, node_id: u64) -> Vec let current_node = ctx.node_map[¤t_node_id]; let mut params = Vec::new(); for param in current_node.get_parameters().unwrap() { - params.push(param.get_name().unwrap().to_string()); + params.push(param.get_name().unwrap().to_string().unwrap()); } accumulator.push(params); diff --git a/capnpc/test/dynamic.rs b/capnpc/test/dynamic.rs index 4bd4fcca6..815cc9c74 100644 --- a/capnpc/test/dynamic.rs +++ b/capnpc/test/dynamic.rs @@ -57,7 +57,7 @@ fn test_unions() { let mut message = message::Builder::new_default(); let mut root: test_union::Builder<'_> = message.init_root(); root.reborrow().get_union0().set_u0f1s32(1234567); - root.reborrow().get_union1().set_u1f1sp("foo"); + root.reborrow().get_union1().set_u1f1sp("foo".into()); root.reborrow().get_union2().set_u2f0s1(true); root.reborrow() .get_union3() @@ -119,11 +119,11 @@ fn test_unions() { let w = u.reborrow().which().unwrap().unwrap(); assert_eq!("u1f1sp", w.get_proto().get_name().unwrap()); assert_eq!( - "foo", u.get(w) .unwrap() .into_reader() - .downcast::>() + .downcast::>(), + "foo" ); } { @@ -236,7 +236,7 @@ fn test_stringify() { let mut root: test_all_types::Builder<'_> = message.init_root(); root.set_int8_field(3); root.set_enum_field(TestEnum::Bar); - root.set_text_field("hello world"); + root.set_text_field("hello world".into()); root.set_data_field(&[1, 2, 3, 4, 5, 127, 255]); let mut bool_list = root.reborrow().init_bool_list(2); bool_list.set(0, false); diff --git a/capnpc/test/test.rs b/capnpc/test/test.rs index 6f88f3675..a4645f58c 100644 --- a/capnpc/test/test.rs +++ b/capnpc/test/test.rs @@ -245,7 +245,7 @@ mod tests { let mut test_blob = message.init_root::>(); assert_eq!(test_blob.has_text_field(), false); - test_blob.set_text_field("abcdefghi"); + test_blob.set_text_field("abcdefghi".into()); assert_eq!(test_blob.has_text_field(), true); assert_eq!(test_blob.has_data_field(), false); @@ -264,7 +264,7 @@ mod tests { { let mut text = test_blob.reborrow().init_text_field(10); - assert_eq!(&*text, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); + assert_eq!(text, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); text.push_str("aabbccddee"); } @@ -357,8 +357,8 @@ mod tests { { let mut text_list = test_complex_list.reborrow().init_text_list(2); - text_list.set(0, "garply"); - text_list.set(1, "foo"); + text_list.set(0, "garply".into()); + text_list.set(1, "foo".into()); } { @@ -413,7 +413,7 @@ mod tests { { let text_list_list = test_complex_list.reborrow().init_text_list_list(1); - text_list_list.init(0, 1).set(0, "abc"); + text_list_list.init(0, 1).set(0, b"abc".into()); } { @@ -467,7 +467,8 @@ mod tests { assert!(enum_list_list.get(1).unwrap().get(0) == Ok(AnEnum::Foo)); assert!(enum_list_list.get(1).unwrap().get(1) == Ok(AnEnum::Qux)); - assert!( + assert_eq!( + "abc", complex_list_reader .get_text_list_list() .unwrap() @@ -475,7 +476,6 @@ mod tests { .unwrap() .get(0) .unwrap() - == "abc" ); assert!( complex_list_reader @@ -571,7 +571,7 @@ mod tests { { let mut sub_builder = test_defaults.reborrow().get_struct_field().unwrap(); - sub_builder.set_text_field("garply"); + sub_builder.set_text_field(b"garply".into()); } assert_eq!(test_defaults.reborrow().get_bool_field(), false); @@ -595,7 +595,7 @@ mod tests { { let sub_builder = test_defaults.reborrow().get_struct_field().unwrap(); - assert_eq!("garply", &*sub_builder.get_text_field().unwrap()); + assert_eq!("garply", sub_builder.get_text_field().unwrap()); } } } @@ -778,7 +778,7 @@ mod tests { // Check setters - test_set.set_text("foo"); + test_set.set_text(b"foo".into()); test_set.set_data(&[42]); { let mut b = test_set.reborrow().init_list(3); @@ -787,7 +787,10 @@ mod tests { b.set(2, 3); } test_set.reborrow().init_empty_struct(); - test_set.reborrow().init_simple_struct().set_field("buzz"); + test_set + .reborrow() + .init_simple_struct() + .set_field(b"buzz".into()); { let mut b = test_set.reborrow().init_any(); b.set_as("dyn")?; @@ -825,7 +828,7 @@ mod tests { let unset_reader = test_unset.into_reader(); assert!(unset_reader.get_text()?.is_none()); - assert_eq!(set_reader.get_text()?, Some("foo")); + assert_eq!(set_reader.get_text()?, Some(capnp::text::Reader(b"foo"))); assert!(unset_reader.get_data()?.is_none()); assert_eq!(set_reader.get_data()?, Some(&[42][..])); @@ -841,7 +844,7 @@ mod tests { assert!(unset_reader.get_simple_struct()?.is_none()); let r = set_reader.get_simple_struct()?.expect("is some"); - assert_eq!(r.get_field()?, Some("buzz")); + assert_eq!(r.get_field()?, Some(capnp::text::Reader(b"buzz"))); assert!(unset_reader.get_any().is_none()); assert!(set_reader.get_any().is_some()); @@ -858,7 +861,7 @@ mod tests { { let branded_field = branded.reborrow().init_branded_field(); let mut foo = branded_field.init_generic_field(); - foo.set_text_field("blah"); + foo.set_text_field("blah".into()); } let reader = branded.into_reader(); @@ -882,10 +885,10 @@ mod tests { let mut branded = message_for_brand.init_root::>(); { let mut baz = branded.reborrow().init_baz_field(); - baz.set_foo_field("blah").unwrap(); + baz.set_foo_field("blah".into()).unwrap(); let mut bar = baz.init_bar_field(); - bar.set_text_field("some text"); - bar.set_data_field("some data".as_bytes()); + bar.set_text_field("some text".into()); + bar.set_data_field(b"some data"); } let reader = branded.into_reader(); @@ -904,7 +907,7 @@ mod tests { .unwrap() ); assert_eq!( - "some data".as_bytes(), + b"some data", reader .get_baz_field() .unwrap() @@ -923,7 +926,11 @@ mod tests { let mut root: test_generics::Builder<'_, test_all_types::Owned, text::Owned> = message.init_root(); init_test_message(root.reborrow().get_foo().unwrap()); - root.reborrow().get_dub().unwrap().set_foo("Hello").unwrap(); + root.reborrow() + .get_dub() + .unwrap() + .set_foo("Hello".into()) + .unwrap(); { let mut bar: ::capnp::primitive_list::Builder<'_, u8> = root.reborrow().get_dub().unwrap().initn_bar(1); @@ -1083,7 +1090,10 @@ mod tests { } assert_eq!(union_struct.reborrow().get_union0().has_u0f0sp(), false); - union_struct.reborrow().init_union0().set_u0f0sp("abcdef"); + union_struct + .reborrow() + .init_union0() + .set_u0f0sp("abcdef".into()); assert_eq!(union_struct.get_union0().has_u0f0sp(), true); } @@ -1105,7 +1115,8 @@ mod tests { panic!("") }; - let test_union_defaults::inner2::C(Ok("grault")) = reader.get_inner2().which().unwrap() + let test_union_defaults::inner2::C(Ok(capnp::text::Reader(b"grault"))) = + reader.get_inner2().which().unwrap() else { panic!("") }; @@ -1214,8 +1225,8 @@ mod tests { let mut old_version = message.init_root::>(); old_version.set_old1(123); let mut names = old_version.init_old4(2); - names.set(0, "alice"); - names.set(1, "bob"); + names.set(0, "alice".into()); + names.set(1, "bob".into()); } { let mut new_version = message.get_root::>().unwrap(); @@ -1227,11 +1238,8 @@ mod tests { let mut names = new_version.get_old4().unwrap(); assert_eq!(names.len(), 2); - assert_eq!( - names.reborrow().get(0).get_text_field().unwrap().as_ref(), - "alice" - ); - assert_eq!(names.get(1).get_text_field().unwrap().as_ref(), "bob"); + assert_eq!(names.reborrow().get(0).get_text_field().unwrap(), "alice"); + assert_eq!(names.get(1).get_text_field().unwrap(), "bob"); } } @@ -1244,8 +1252,8 @@ mod tests { let mut new_version = message.init_root::>(); new_version.set_old1(123); let mut names = new_version.init_old4(2); - names.reborrow().get(0).set_text_field("alice"); - names.get(1).set_text_field("bob"); + names.reborrow().get(0).set_text_field("alice".into()); + names.get(1).set_text_field("bob".into()); } { let old_version = message @@ -1316,9 +1324,9 @@ mod tests { .reborrow() .get_any_pointer_field() .initn_as::<::capnp::text_list::Builder<'_>>(3); - list.set(0, "foo"); - list.set(1, "bar"); - list.set(2, "baz"); + list.set(0, "foo".into()); + list.set(1, "bar".into()); + list.set(2, "baz".into()); } { let mut l = root @@ -1326,9 +1334,9 @@ mod tests { .get_as::<::capnp::struct_list::Builder<'_, test_lists::struct_p::Owned>>() .unwrap(); assert_eq!(3, l.len()); - assert_eq!("foo", &*l.reborrow().get(0).get_f().unwrap()); - assert_eq!("bar", &*l.reborrow().get(1).get_f().unwrap()); - assert_eq!("baz", &*l.reborrow().get(2).get_f().unwrap()); + assert_eq!("foo", l.reborrow().get(0).get_f().unwrap()); + assert_eq!("bar", l.reborrow().get(1).get_f().unwrap()); + assert_eq!("baz", l.reborrow().get(2).get_f().unwrap()); } } } @@ -1376,10 +1384,7 @@ mod tests { message.get_root().unwrap(); assert_eq!(new_version.len(), 1); assert_eq!(new_version.reborrow().get(0).get_old1(), 0xab); - assert_eq!( - &*new_version.reborrow().get(0).get_old2().unwrap(), - "hello!!" - ); + assert_eq!(new_version.reborrow().get(0).get_old2().unwrap(), "hello!!"); } { @@ -1918,7 +1923,7 @@ mod tests { let mut message = message::Builder::new_default(); { let mut test = message.init_root::>(); - test.set_text_field("Hello"); + test.set_text_field("Hello".into()); } let reader = message .get_root::>() diff --git a/capnpc/test/test_util.rs b/capnpc/test/test_util.rs index 317444bd6..c5f299f6b 100644 --- a/capnpc/test/test_util.rs +++ b/capnpc/test/test_util.rs @@ -34,7 +34,7 @@ pub fn init_test_message(mut builder: test_all_types::Builder<'_>) { builder.set_u_int64_field(12345678901234567890); builder.set_float32_field(1234.5); builder.set_float64_field(-123e45); - builder.set_text_field("foo"); + builder.set_text_field("foo".into()); builder.set_data_field(b"bar"); { let mut sub_builder = builder.reborrow().init_struct_field(); @@ -50,14 +50,14 @@ pub fn init_test_message(mut builder: test_all_types::Builder<'_>) { sub_builder.set_u_int64_field(345678901234567890); sub_builder.set_float32_field(-1.25e-10); sub_builder.set_float64_field(345f64); - sub_builder.set_text_field("baz"); + sub_builder.set_text_field("baz".into()); sub_builder.set_data_field(b"qux"); { let mut sub_sub_builder = sub_builder.reborrow().init_struct_field(); - sub_sub_builder.set_text_field("nested"); + sub_sub_builder.set_text_field("nested".into()); sub_sub_builder .init_struct_field() - .set_text_field("really nested"); + .set_text_field("really nested".into()); } sub_builder.set_enum_field(TestEnum::Baz); @@ -157,15 +157,15 @@ pub fn init_test_message(mut builder: test_all_types::Builder<'_>) { struct_list .reborrow() .get(0) - .set_text_field("x structlist 1"); + .set_text_field("x structlist 1".into()); struct_list .reborrow() .get(1) - .set_text_field("x structlist 2"); + .set_text_field("x structlist 2".into()); struct_list .reborrow() .get(2) - .set_text_field("x structlist 3"); + .set_text_field("x structlist 3".into()); } let mut enum_list = sub_builder.reborrow().init_enum_list(3); @@ -189,9 +189,18 @@ pub fn init_test_message(mut builder: test_all_types::Builder<'_>) { { let mut struct_list = builder.reborrow().init_struct_list(3); - struct_list.reborrow().get(0).set_text_field("structlist 1"); - struct_list.reborrow().get(1).set_text_field("structlist 2"); - struct_list.reborrow().get(2).set_text_field("structlist 3"); + struct_list + .reborrow() + .get(0) + .set_text_field("structlist 1".into()); + struct_list + .reborrow() + .get(1) + .set_text_field("structlist 2".into()); + struct_list + .reborrow() + .get(2) + .set_text_field("structlist 3".into()); } // ... @@ -218,7 +227,7 @@ check_test_message_impl(($mod:ident::$typ:ident) => ( assert_eq!(12345678901234567890, reader.reborrow().get_u_int64_field()); assert_eq!(1234.5, reader.reborrow().get_float32_field()); assert_eq!(-123e45, reader.reborrow().get_float64_field()); - assert_eq!("foo", &*reader.reborrow().get_text_field().unwrap()); + assert_eq!("foo", reader.reborrow().get_text_field().unwrap()); assert_eq!(b"bar", &*reader.reborrow().get_data_field().unwrap()); { let mut sub_reader = reader.reborrow().get_struct_field().unwrap(); @@ -234,13 +243,14 @@ check_test_message_impl(($mod:ident::$typ:ident) => ( assert_eq!(345678901234567890, sub_reader.reborrow().get_u_int64_field()); assert_eq!(-1.25e-10, sub_reader.reborrow().get_float32_field()); assert_eq!(345f64, sub_reader.reborrow().get_float64_field()); - assert_eq!("baz", &*sub_reader.reborrow().get_text_field().unwrap()); + assert_eq!("baz", sub_reader.reborrow().get_text_field().unwrap()); assert_eq!(b"qux", &*sub_reader.reborrow().get_data_field().unwrap()); { let mut sub_sub_reader = sub_reader.reborrow().get_struct_field().unwrap(); - assert_eq!("nested", &*sub_sub_reader.reborrow().get_text_field().unwrap()); - assert_eq!("really nested", &*sub_sub_reader.get_struct_field().unwrap() - .get_text_field().unwrap()); + assert_eq!("nested", sub_sub_reader.reborrow().get_text_field().unwrap()); + assert_eq!("really nested", + sub_sub_reader.get_struct_field().unwrap() + .get_text_field().unwrap()); } assert!(Ok(TestEnum::Baz) == sub_reader.reborrow().get_enum_field()); assert_eq!(false, sub_reader.reborrow().has_interface_field()); @@ -355,9 +365,9 @@ check_test_message_impl(($mod:ident::$typ:ident) => ( { let mut struct_list = sub_reader.reborrow().get_struct_list().unwrap(); assert_eq!(3, struct_list.len()); - assert_eq!("x structlist 1", &*struct_list.reborrow().get(0).get_text_field().unwrap()); - assert_eq!("x structlist 2", &*struct_list.reborrow().get(1).get_text_field().unwrap()); - assert_eq!("x structlist 3", &*struct_list.reborrow().get(2).get_text_field().unwrap()); + assert_eq!("x structlist 1", struct_list.reborrow().get(0).get_text_field().unwrap()); + assert_eq!("x structlist 2", struct_list.reborrow().get(1).get_text_field().unwrap()); + assert_eq!("x structlist 3", struct_list.reborrow().get(2).get_text_field().unwrap()); } { @@ -386,9 +396,9 @@ check_test_message_impl(($mod:ident::$typ:ident) => ( { let mut struct_list = reader.reborrow().get_struct_list().unwrap(); assert_eq!(3, struct_list.len()); - assert_eq!("structlist 1", &*struct_list.reborrow().get(0).get_text_field().unwrap()); - assert_eq!("structlist 2", &*struct_list.reborrow().get(1).get_text_field().unwrap()); - assert_eq!("structlist 3", &*struct_list.reborrow().get(2).get_text_field().unwrap()); + assert_eq!("structlist 1", struct_list.reborrow().get(0).get_text_field().unwrap()); + assert_eq!("structlist 2", struct_list.reborrow().get(1).get_text_field().unwrap()); + assert_eq!("structlist 3", struct_list.reborrow().get(2).get_text_field().unwrap()); } diff --git a/example/addressbook/addressbook.rs b/example/addressbook/addressbook.rs index b5ba1f5cc..0b5eb29b6 100644 --- a/example/addressbook/addressbook.rs +++ b/example/addressbook/addressbook.rs @@ -37,32 +37,32 @@ pub mod addressbook { { let mut alice = people.reborrow().get(0); alice.set_id(123); - alice.set_name("Alice"); - alice.set_email("alice@example.com"); + alice.set_name("Alice".into()); + alice.set_email("alice@example.com".into()); { let mut alice_phones = alice.reborrow().init_phones(1); - alice_phones.reborrow().get(0).set_number("555-1212"); + alice_phones.reborrow().get(0).set_number("555-1212".into()); alice_phones .reborrow() .get(0) .set_type(person::phone_number::Type::Mobile); } - alice.get_employment().set_school("MIT"); + alice.get_employment().set_school("MIT".into()); } { let mut bob = people.get(1); bob.set_id(456); - bob.set_name("Bob"); - bob.set_email("bob@example.com"); + bob.set_name("Bob".into()); + bob.set_email("bob@example.com".into()); { let mut bob_phones = bob.reborrow().init_phones(2); - bob_phones.reborrow().get(0).set_number("555-4567"); + bob_phones.reborrow().get(0).set_number("555-4567".into()); bob_phones .reborrow() .get(0) .set_type(person::phone_number::Type::Home); - bob_phones.reborrow().get(1).set_number("555-7654"); + bob_phones.reborrow().get(1).set_number("555-7654".into()); bob_phones .reborrow() .get(1) @@ -84,7 +84,11 @@ pub mod addressbook { let address_book = message_reader.get_root::()?; for person in address_book.get_people()? { - println!("{}: {}", person.get_name()?, person.get_email()?); + println!( + "{}: {}", + person.get_name()?.to_str()?, + person.get_email()?.to_str()? + ); for phone in person.get_phones()? { let type_name = match phone.get_type() { Ok(person::phone_number::Type::Mobile) => "mobile", @@ -92,17 +96,17 @@ pub mod addressbook { Ok(person::phone_number::Type::Work) => "work", Err(::capnp::NotInSchema(_)) => "UNKNOWN", }; - println!(" {} phone: {}", type_name, phone.get_number()?); + println!(" {} phone: {}", type_name, phone.get_number()?.to_str()?); } match person.get_employment().which() { Ok(person::employment::Unemployed(())) => { println!(" unemployed"); } Ok(person::employment::Employer(employer)) => { - println!(" employer: {}", employer?); + println!(" employer: {}", employer?.to_str()?); } Ok(person::employment::School(school)) => { - println!(" student at: {}", school?); + println!(" student at: {}", school?.to_str()?); } Ok(person::employment::SelfEmployed(())) => { println!(" self-employed"); diff --git a/example/addressbook_send/addressbook_send.rs b/example/addressbook_send/addressbook_send.rs index 65fdc718a..708ea8c35 100644 --- a/example/addressbook_send/addressbook_send.rs +++ b/example/addressbook_send/addressbook_send.rs @@ -41,32 +41,32 @@ pub mod addressbook { { let mut alice = people.reborrow().get(0); alice.set_id(123); - alice.set_name("Alice"); - alice.set_email("alice@example.com"); + alice.set_name("Alice".into()); + alice.set_email("alice@example.com".into()); { let mut alice_phones = alice.reborrow().init_phones(1); - alice_phones.reborrow().get(0).set_number("555-1212"); + alice_phones.reborrow().get(0).set_number("555-1212".into()); alice_phones .reborrow() .get(0) .set_type(person::phone_number::Type::Mobile); } - alice.get_employment().set_school("MIT"); + alice.get_employment().set_school("MIT".into()); } { let mut bob = people.get(1); bob.set_id(456); - bob.set_name("Bob"); - bob.set_email("bob@example.com"); + bob.set_name("Bob".into()); + bob.set_email("bob@example.com".into()); { let mut bob_phones = bob.reborrow().init_phones(2); - bob_phones.reborrow().get(0).set_number("555-4567"); + bob_phones.reborrow().get(0).set_number("555-4567".into()); bob_phones .reborrow() .get(0) .set_type(person::phone_number::Type::Home); - bob_phones.reborrow().get(1).set_number("555-7654"); + bob_phones.reborrow().get(1).set_number("555-7654".into()); bob_phones .reborrow() .get(1)