How to wrap a borrowed value in a newtype that is also a borrowed value?
I am trying to use the newtype pattern to wrap a pre-existing type. That inner type has a modify
method which lets us work with a borrowed mutable value in a callback:
struct Val;
struct Inner(Val);
impl Inner {
fn modify<F>(&self, f: F)
where F: FnOnce(&mut Val) -> &mut Val { … }
}
Now I want to provide a very similar method on my newtype Outer
, which however should not work on Val
s but again a newtype wrapper WrappedVal
:
struct Outer(Inner);
struct WrappedVal(Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| f(/* ??? */));
}
}
This code is a reduced example from the original API. I don't know why the reference is returned from the closure, maybe to facilitate chaining, but it shouldn't be necessary. It takes &self
because it uses internal mutability - it's a type representing a peripheral register on an embedded system
How do I get a &mut WrappedVal
from a &mut Val
?
I have tried various things, but all were busted by the borrow-checker. I cannot move the Val
out of the mutable reference to construct a proper WrappedVal
, and I couldn't get lifetimes to compile either when experimenting around with struct WrappedVal(&'? mut Val)
(which I don't really want actually, since they are complicating a trait implementation).
I eventually got it to compile (see Rust playground demo) using the absolute horror of
self.0.modify(|v| unsafe {
(f((v as *mut Val as *mut WrappedVal).as_mut().unwrap()) as *mut WrappedVal as *mut Val)
.as_mut()
.unwrap()
});
but surely there must be a better way?
reference rust borrowing newtype
add a comment |
I am trying to use the newtype pattern to wrap a pre-existing type. That inner type has a modify
method which lets us work with a borrowed mutable value in a callback:
struct Val;
struct Inner(Val);
impl Inner {
fn modify<F>(&self, f: F)
where F: FnOnce(&mut Val) -> &mut Val { … }
}
Now I want to provide a very similar method on my newtype Outer
, which however should not work on Val
s but again a newtype wrapper WrappedVal
:
struct Outer(Inner);
struct WrappedVal(Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| f(/* ??? */));
}
}
This code is a reduced example from the original API. I don't know why the reference is returned from the closure, maybe to facilitate chaining, but it shouldn't be necessary. It takes &self
because it uses internal mutability - it's a type representing a peripheral register on an embedded system
How do I get a &mut WrappedVal
from a &mut Val
?
I have tried various things, but all were busted by the borrow-checker. I cannot move the Val
out of the mutable reference to construct a proper WrappedVal
, and I couldn't get lifetimes to compile either when experimenting around with struct WrappedVal(&'? mut Val)
(which I don't really want actually, since they are complicating a trait implementation).
I eventually got it to compile (see Rust playground demo) using the absolute horror of
self.0.modify(|v| unsafe {
(f((v as *mut Val as *mut WrappedVal).as_mut().unwrap()) as *mut WrappedVal as *mut Val)
.as_mut()
.unwrap()
});
but surely there must be a better way?
reference rust borrowing newtype
add a comment |
I am trying to use the newtype pattern to wrap a pre-existing type. That inner type has a modify
method which lets us work with a borrowed mutable value in a callback:
struct Val;
struct Inner(Val);
impl Inner {
fn modify<F>(&self, f: F)
where F: FnOnce(&mut Val) -> &mut Val { … }
}
Now I want to provide a very similar method on my newtype Outer
, which however should not work on Val
s but again a newtype wrapper WrappedVal
:
struct Outer(Inner);
struct WrappedVal(Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| f(/* ??? */));
}
}
This code is a reduced example from the original API. I don't know why the reference is returned from the closure, maybe to facilitate chaining, but it shouldn't be necessary. It takes &self
because it uses internal mutability - it's a type representing a peripheral register on an embedded system
How do I get a &mut WrappedVal
from a &mut Val
?
I have tried various things, but all were busted by the borrow-checker. I cannot move the Val
out of the mutable reference to construct a proper WrappedVal
, and I couldn't get lifetimes to compile either when experimenting around with struct WrappedVal(&'? mut Val)
(which I don't really want actually, since they are complicating a trait implementation).
I eventually got it to compile (see Rust playground demo) using the absolute horror of
self.0.modify(|v| unsafe {
(f((v as *mut Val as *mut WrappedVal).as_mut().unwrap()) as *mut WrappedVal as *mut Val)
.as_mut()
.unwrap()
});
but surely there must be a better way?
reference rust borrowing newtype
I am trying to use the newtype pattern to wrap a pre-existing type. That inner type has a modify
method which lets us work with a borrowed mutable value in a callback:
struct Val;
struct Inner(Val);
impl Inner {
fn modify<F>(&self, f: F)
where F: FnOnce(&mut Val) -> &mut Val { … }
}
Now I want to provide a very similar method on my newtype Outer
, which however should not work on Val
s but again a newtype wrapper WrappedVal
:
struct Outer(Inner);
struct WrappedVal(Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| f(/* ??? */));
}
}
This code is a reduced example from the original API. I don't know why the reference is returned from the closure, maybe to facilitate chaining, but it shouldn't be necessary. It takes &self
because it uses internal mutability - it's a type representing a peripheral register on an embedded system
How do I get a &mut WrappedVal
from a &mut Val
?
I have tried various things, but all were busted by the borrow-checker. I cannot move the Val
out of the mutable reference to construct a proper WrappedVal
, and I couldn't get lifetimes to compile either when experimenting around with struct WrappedVal(&'? mut Val)
(which I don't really want actually, since they are complicating a trait implementation).
I eventually got it to compile (see Rust playground demo) using the absolute horror of
self.0.modify(|v| unsafe {
(f((v as *mut Val as *mut WrappedVal).as_mut().unwrap()) as *mut WrappedVal as *mut Val)
.as_mut()
.unwrap()
});
but surely there must be a better way?
reference rust borrowing newtype
reference rust borrowing newtype
edited Jan 2 at 18:53
Shepmaster
158k15320462
158k15320462
asked Jan 1 at 22:59
BergiBergi
377k62573903
377k62573903
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
There is no safe way with your current definition, and your unsafe code is not guaranteed to be safe. There's no contract that the layout of a WrappedVal
matches that of a Val
, even though that's all it holds.
Solution not using unsafe
Don't do it. Instead, wrap the reference:
struct WrappedVal<'a>(&'a mut Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(WrappedVal) -> WrappedVal,
{
self.0.modify(|v| f(WrappedVal(v)).0)
}
}
Solution using unsafe
You can state that your type has the same representation as the type it wraps, making the pointers compatible via repr(transparent)
:
#[repr(transparent)]
struct WrappedVal(given::Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| {
// Insert documentation why **you** think this is safe
// instead of copy-pasting from Stack Overflow
let wv = unsafe { &mut *(v as *mut given::Val as *mut WrappedVal) };
let wv = f(wv);
unsafe { &mut *(wv as *mut WrappedVal as *mut given::Val) }
})
}
}
With repr(transparent)
in place, the two pointers are interchangable. I ran a quick test with Miri and your full example and didn't receive any errors, but that's not a silver bullet that I didn't mess something else up.
Thanks for mentioningrepr(transparent)
, I didn't know about that. How should I argue that the cast is safe - surely if the values have the same memory representation, I should be able to call methods from both types on the same memory location? Do I need to assess any other aspect?
– Bergi
Jan 2 at 11:47
I had attempted the safe solution where a&mut Val
is wrapped, but as hinted at in the question I couldn't get the lifetimes right. I don't want to litter my code (especiallyOuter
) with lifetime parameters that will only be needed locally in one method forWrappedVal
, am I approaching this wrong? I'm already surprised that you could omit the lifetime argument inFnOnce(WrappedVal) -> WrappedVal
.
– Bergi
Jan 2 at 11:52
1
@Bergi yes, using lifetimes like that in a trait is beyond what Rust can currently express; generic associated types (GATs) need to be implemented first. Traits are more complicated than plain functions due to their flexibility.
– Shepmaster
Jan 2 at 19:00
@Bergi My comment inside the code is meant to dissuade future people from just copy-pasting the code without reading the rest of the answer. My belief that the code is safe comes from the usage ofrepr(transparent)
, so that's what I'd use in my comment, yeah.
– Shepmaster
Jan 2 at 19:11
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53999600%2fhow-to-wrap-a-borrowed-value-in-a-newtype-that-is-also-a-borrowed-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
There is no safe way with your current definition, and your unsafe code is not guaranteed to be safe. There's no contract that the layout of a WrappedVal
matches that of a Val
, even though that's all it holds.
Solution not using unsafe
Don't do it. Instead, wrap the reference:
struct WrappedVal<'a>(&'a mut Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(WrappedVal) -> WrappedVal,
{
self.0.modify(|v| f(WrappedVal(v)).0)
}
}
Solution using unsafe
You can state that your type has the same representation as the type it wraps, making the pointers compatible via repr(transparent)
:
#[repr(transparent)]
struct WrappedVal(given::Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| {
// Insert documentation why **you** think this is safe
// instead of copy-pasting from Stack Overflow
let wv = unsafe { &mut *(v as *mut given::Val as *mut WrappedVal) };
let wv = f(wv);
unsafe { &mut *(wv as *mut WrappedVal as *mut given::Val) }
})
}
}
With repr(transparent)
in place, the two pointers are interchangable. I ran a quick test with Miri and your full example and didn't receive any errors, but that's not a silver bullet that I didn't mess something else up.
Thanks for mentioningrepr(transparent)
, I didn't know about that. How should I argue that the cast is safe - surely if the values have the same memory representation, I should be able to call methods from both types on the same memory location? Do I need to assess any other aspect?
– Bergi
Jan 2 at 11:47
I had attempted the safe solution where a&mut Val
is wrapped, but as hinted at in the question I couldn't get the lifetimes right. I don't want to litter my code (especiallyOuter
) with lifetime parameters that will only be needed locally in one method forWrappedVal
, am I approaching this wrong? I'm already surprised that you could omit the lifetime argument inFnOnce(WrappedVal) -> WrappedVal
.
– Bergi
Jan 2 at 11:52
1
@Bergi yes, using lifetimes like that in a trait is beyond what Rust can currently express; generic associated types (GATs) need to be implemented first. Traits are more complicated than plain functions due to their flexibility.
– Shepmaster
Jan 2 at 19:00
@Bergi My comment inside the code is meant to dissuade future people from just copy-pasting the code without reading the rest of the answer. My belief that the code is safe comes from the usage ofrepr(transparent)
, so that's what I'd use in my comment, yeah.
– Shepmaster
Jan 2 at 19:11
add a comment |
There is no safe way with your current definition, and your unsafe code is not guaranteed to be safe. There's no contract that the layout of a WrappedVal
matches that of a Val
, even though that's all it holds.
Solution not using unsafe
Don't do it. Instead, wrap the reference:
struct WrappedVal<'a>(&'a mut Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(WrappedVal) -> WrappedVal,
{
self.0.modify(|v| f(WrappedVal(v)).0)
}
}
Solution using unsafe
You can state that your type has the same representation as the type it wraps, making the pointers compatible via repr(transparent)
:
#[repr(transparent)]
struct WrappedVal(given::Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| {
// Insert documentation why **you** think this is safe
// instead of copy-pasting from Stack Overflow
let wv = unsafe { &mut *(v as *mut given::Val as *mut WrappedVal) };
let wv = f(wv);
unsafe { &mut *(wv as *mut WrappedVal as *mut given::Val) }
})
}
}
With repr(transparent)
in place, the two pointers are interchangable. I ran a quick test with Miri and your full example and didn't receive any errors, but that's not a silver bullet that I didn't mess something else up.
Thanks for mentioningrepr(transparent)
, I didn't know about that. How should I argue that the cast is safe - surely if the values have the same memory representation, I should be able to call methods from both types on the same memory location? Do I need to assess any other aspect?
– Bergi
Jan 2 at 11:47
I had attempted the safe solution where a&mut Val
is wrapped, but as hinted at in the question I couldn't get the lifetimes right. I don't want to litter my code (especiallyOuter
) with lifetime parameters that will only be needed locally in one method forWrappedVal
, am I approaching this wrong? I'm already surprised that you could omit the lifetime argument inFnOnce(WrappedVal) -> WrappedVal
.
– Bergi
Jan 2 at 11:52
1
@Bergi yes, using lifetimes like that in a trait is beyond what Rust can currently express; generic associated types (GATs) need to be implemented first. Traits are more complicated than plain functions due to their flexibility.
– Shepmaster
Jan 2 at 19:00
@Bergi My comment inside the code is meant to dissuade future people from just copy-pasting the code without reading the rest of the answer. My belief that the code is safe comes from the usage ofrepr(transparent)
, so that's what I'd use in my comment, yeah.
– Shepmaster
Jan 2 at 19:11
add a comment |
There is no safe way with your current definition, and your unsafe code is not guaranteed to be safe. There's no contract that the layout of a WrappedVal
matches that of a Val
, even though that's all it holds.
Solution not using unsafe
Don't do it. Instead, wrap the reference:
struct WrappedVal<'a>(&'a mut Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(WrappedVal) -> WrappedVal,
{
self.0.modify(|v| f(WrappedVal(v)).0)
}
}
Solution using unsafe
You can state that your type has the same representation as the type it wraps, making the pointers compatible via repr(transparent)
:
#[repr(transparent)]
struct WrappedVal(given::Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| {
// Insert documentation why **you** think this is safe
// instead of copy-pasting from Stack Overflow
let wv = unsafe { &mut *(v as *mut given::Val as *mut WrappedVal) };
let wv = f(wv);
unsafe { &mut *(wv as *mut WrappedVal as *mut given::Val) }
})
}
}
With repr(transparent)
in place, the two pointers are interchangable. I ran a quick test with Miri and your full example and didn't receive any errors, but that's not a silver bullet that I didn't mess something else up.
There is no safe way with your current definition, and your unsafe code is not guaranteed to be safe. There's no contract that the layout of a WrappedVal
matches that of a Val
, even though that's all it holds.
Solution not using unsafe
Don't do it. Instead, wrap the reference:
struct WrappedVal<'a>(&'a mut Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(WrappedVal) -> WrappedVal,
{
self.0.modify(|v| f(WrappedVal(v)).0)
}
}
Solution using unsafe
You can state that your type has the same representation as the type it wraps, making the pointers compatible via repr(transparent)
:
#[repr(transparent)]
struct WrappedVal(given::Val);
impl Outer {
fn modify<F>(&self, f: F)
where
F: FnOnce(&mut WrappedVal) -> &mut WrappedVal,
{
self.0.modify(|v| {
// Insert documentation why **you** think this is safe
// instead of copy-pasting from Stack Overflow
let wv = unsafe { &mut *(v as *mut given::Val as *mut WrappedVal) };
let wv = f(wv);
unsafe { &mut *(wv as *mut WrappedVal as *mut given::Val) }
})
}
}
With repr(transparent)
in place, the two pointers are interchangable. I ran a quick test with Miri and your full example and didn't receive any errors, but that's not a silver bullet that I didn't mess something else up.
edited Jan 2 at 19:10
answered Jan 1 at 23:52
ShepmasterShepmaster
158k15320462
158k15320462
Thanks for mentioningrepr(transparent)
, I didn't know about that. How should I argue that the cast is safe - surely if the values have the same memory representation, I should be able to call methods from both types on the same memory location? Do I need to assess any other aspect?
– Bergi
Jan 2 at 11:47
I had attempted the safe solution where a&mut Val
is wrapped, but as hinted at in the question I couldn't get the lifetimes right. I don't want to litter my code (especiallyOuter
) with lifetime parameters that will only be needed locally in one method forWrappedVal
, am I approaching this wrong? I'm already surprised that you could omit the lifetime argument inFnOnce(WrappedVal) -> WrappedVal
.
– Bergi
Jan 2 at 11:52
1
@Bergi yes, using lifetimes like that in a trait is beyond what Rust can currently express; generic associated types (GATs) need to be implemented first. Traits are more complicated than plain functions due to their flexibility.
– Shepmaster
Jan 2 at 19:00
@Bergi My comment inside the code is meant to dissuade future people from just copy-pasting the code without reading the rest of the answer. My belief that the code is safe comes from the usage ofrepr(transparent)
, so that's what I'd use in my comment, yeah.
– Shepmaster
Jan 2 at 19:11
add a comment |
Thanks for mentioningrepr(transparent)
, I didn't know about that. How should I argue that the cast is safe - surely if the values have the same memory representation, I should be able to call methods from both types on the same memory location? Do I need to assess any other aspect?
– Bergi
Jan 2 at 11:47
I had attempted the safe solution where a&mut Val
is wrapped, but as hinted at in the question I couldn't get the lifetimes right. I don't want to litter my code (especiallyOuter
) with lifetime parameters that will only be needed locally in one method forWrappedVal
, am I approaching this wrong? I'm already surprised that you could omit the lifetime argument inFnOnce(WrappedVal) -> WrappedVal
.
– Bergi
Jan 2 at 11:52
1
@Bergi yes, using lifetimes like that in a trait is beyond what Rust can currently express; generic associated types (GATs) need to be implemented first. Traits are more complicated than plain functions due to their flexibility.
– Shepmaster
Jan 2 at 19:00
@Bergi My comment inside the code is meant to dissuade future people from just copy-pasting the code without reading the rest of the answer. My belief that the code is safe comes from the usage ofrepr(transparent)
, so that's what I'd use in my comment, yeah.
– Shepmaster
Jan 2 at 19:11
Thanks for mentioning
repr(transparent)
, I didn't know about that. How should I argue that the cast is safe - surely if the values have the same memory representation, I should be able to call methods from both types on the same memory location? Do I need to assess any other aspect?– Bergi
Jan 2 at 11:47
Thanks for mentioning
repr(transparent)
, I didn't know about that. How should I argue that the cast is safe - surely if the values have the same memory representation, I should be able to call methods from both types on the same memory location? Do I need to assess any other aspect?– Bergi
Jan 2 at 11:47
I had attempted the safe solution where a
&mut Val
is wrapped, but as hinted at in the question I couldn't get the lifetimes right. I don't want to litter my code (especially Outer
) with lifetime parameters that will only be needed locally in one method for WrappedVal
, am I approaching this wrong? I'm already surprised that you could omit the lifetime argument in FnOnce(WrappedVal) -> WrappedVal
.– Bergi
Jan 2 at 11:52
I had attempted the safe solution where a
&mut Val
is wrapped, but as hinted at in the question I couldn't get the lifetimes right. I don't want to litter my code (especially Outer
) with lifetime parameters that will only be needed locally in one method for WrappedVal
, am I approaching this wrong? I'm already surprised that you could omit the lifetime argument in FnOnce(WrappedVal) -> WrappedVal
.– Bergi
Jan 2 at 11:52
1
1
@Bergi yes, using lifetimes like that in a trait is beyond what Rust can currently express; generic associated types (GATs) need to be implemented first. Traits are more complicated than plain functions due to their flexibility.
– Shepmaster
Jan 2 at 19:00
@Bergi yes, using lifetimes like that in a trait is beyond what Rust can currently express; generic associated types (GATs) need to be implemented first. Traits are more complicated than plain functions due to their flexibility.
– Shepmaster
Jan 2 at 19:00
@Bergi My comment inside the code is meant to dissuade future people from just copy-pasting the code without reading the rest of the answer. My belief that the code is safe comes from the usage of
repr(transparent)
, so that's what I'd use in my comment, yeah.– Shepmaster
Jan 2 at 19:11
@Bergi My comment inside the code is meant to dissuade future people from just copy-pasting the code without reading the rest of the answer. My belief that the code is safe comes from the usage of
repr(transparent)
, so that's what I'd use in my comment, yeah.– Shepmaster
Jan 2 at 19:11
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53999600%2fhow-to-wrap-a-borrowed-value-in-a-newtype-that-is-also-a-borrowed-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown