Александр Мещеряков:
Всем привет! Помогите разобраться с ошибкой десериализации в serde:
Делаю так:
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
#[serde(try_from = "String")]
pub struct CurrencyId(&'static str);
impl TryFrom<String> for CurrencyId {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
Ok(Self(Box::leak(value.into_boxed_str())))
}
}
Но при компиляции простой структуры, которая содержит поле CurrencyId, получаю ошибку:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter
--> test/src/mod.rs:62:5
|
62 | pub currency_id: CurrencyId,
| ^^^
|
note: first, the lifetime cannot outlive the lifetime 'de as defined on the impl at 60:50...
--> test/src/mod.rs:60:50
|
60 | #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
| ^^^^^^^^^^^
= note: ...so that the types are compatible:
expected matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::de::SeqAccess<'_>
found matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::de::SeqAccess<'de>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the types are compatible:
expected matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::Deserialize<'_>
found matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::Deserialize<'static>
Kitsu:
Нельзя десериализовывать static в принципе, это невалидно. 'static - то, что известно на этапе компиляции. Вам подойдет либо owned структура (String), либо строчка с лайфтаймом (&'a str) от того места, откуда идет десериализации (см. доку серде по аттрибутам).
лан, на самом деле на счет "известно на этапе компиляции" я преувеличил, но истина где-то рядом
Александр Мещеряков:
Но там же стоит #[serde(try_from = "String")], какая ему разница, как я получу данный тип из строки? И да, я могу получить статический строковый срез на этапе выполнения.
Kitsu:
А когда вызвать деструктор у строки?
Этот вариант подразумевает, что в коде будет что-то типо:
fn deserialize<D: Deserialize>(d: D) -> Result<MyType> {
let s: String = d.deserialize_string()?;
let my_type = s.try_from()?;
Ok(my_type)
}
s: String - умерла при выходе из функции, а my_type — нет
red75prime:
Главный вопрос. Куда &str должен указывать? serde по понятным причинам не делает Box::leak(), чтобы получить 'static ссылки.
Александр Мещеряков:
try_from делает Box::leak(value.into_boxed_str()), или я не понял, что вы имеете ввиду
Ну у меня есть TryFrom который гарантированно работает - переводит String в CurrencyId, что-то не пойму, почему этого не достаточно
red75prime:
А зачем такое... неортодоксальное решение? Почему не String или Box<str>?
Александр Мещеряков:
Ну мне нужен именно &'static str в CurrencyId, и этот срез будет браться из статического сервиса, но для упрощения примера я сделал Box::leak для получения &'static str из String
Сути ошибки это не изменило...
red75prime:
Хм. Разве что попробовать #[serde(bound(deserialize = "T: DeserializeOwned"))] на поле currency_id. Даже лучше на типе CurrencyId
Александр Мещеряков:
red75prime @kitsu В общем, единственно работающим вариантом оказалось написать собственный десериализатор:
impl<'de> Deserialize<'de> for CurrencyId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
CurrencyId::try_from(value).map_err(<D::Error as de::Error>::custom)
}
}
Мне кажется это баг в serde, он по идее не должен был вообще учитывать статический лайфтайм если я использую TryFrom. Наверное стоит создать issue.
Всем привет! Помогите разобраться с ошибкой десериализации в serde:
Делаю так:
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
#[serde(try_from = "String")]
pub struct CurrencyId(&'static str);
impl TryFrom<String> for CurrencyId {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
Ok(Self(Box::leak(value.into_boxed_str())))
}
}
Но при компиляции простой структуры, которая содержит поле CurrencyId, получаю ошибку:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter
'de due to conflicting requirements--> test/src/mod.rs:62:5
|
62 | pub currency_id: CurrencyId,
| ^^^
|
note: first, the lifetime cannot outlive the lifetime 'de as defined on the impl at 60:50...
--> test/src/mod.rs:60:50
|
60 | #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
| ^^^^^^^^^^^
= note: ...so that the types are compatible:
expected matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::de::SeqAccess<'_>
found matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::de::SeqAccess<'de>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the types are compatible:
expected matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::Deserialize<'_>
found matching::_IMPL_DESERIALIZE_FOR_MatchingStatus::_serde::Deserialize<'static>
Kitsu:
Нельзя десериализовывать static в принципе, это невалидно. 'static - то, что известно на этапе компиляции. Вам подойдет либо owned структура (String), либо строчка с лайфтаймом (&'a str) от того места, откуда идет десериализации (см. доку серде по аттрибутам).
лан, на самом деле на счет "известно на этапе компиляции" я преувеличил, но истина где-то рядом
Александр Мещеряков:
Но там же стоит #[serde(try_from = "String")], какая ему разница, как я получу данный тип из строки? И да, я могу получить статический строковый срез на этапе выполнения.
Kitsu:
А когда вызвать деструктор у строки?
Этот вариант подразумевает, что в коде будет что-то типо:
fn deserialize<D: Deserialize>(d: D) -> Result<MyType> {
let s: String = d.deserialize_string()?;
let my_type = s.try_from()?;
Ok(my_type)
}
s: String - умерла при выходе из функции, а my_type — нет
red75prime:
Главный вопрос. Куда &str должен указывать? serde по понятным причинам не делает Box::leak(), чтобы получить 'static ссылки.
Александр Мещеряков:
try_from делает Box::leak(value.into_boxed_str()), или я не понял, что вы имеете ввиду
Ну у меня есть TryFrom который гарантированно работает - переводит String в CurrencyId, что-то не пойму, почему этого не достаточно
red75prime:
А зачем такое... неортодоксальное решение? Почему не String или Box<str>?
Александр Мещеряков:
Ну мне нужен именно &'static str в CurrencyId, и этот срез будет браться из статического сервиса, но для упрощения примера я сделал Box::leak для получения &'static str из String
Сути ошибки это не изменило...
red75prime:
Хм. Разве что попробовать #[serde(bound(deserialize = "T: DeserializeOwned"))] на поле currency_id. Даже лучше на типе CurrencyId
Александр Мещеряков:
red75prime @kitsu В общем, единственно работающим вариантом оказалось написать собственный десериализатор:
impl<'de> Deserialize<'de> for CurrencyId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
CurrencyId::try_from(value).map_err(<D::Error as de::Error>::custom)
}
}
Мне кажется это баг в serde, он по идее не должен был вообще учитывать статический лайфтайм если я использую TryFrom. Наверное стоит создать issue.
Linker Unsafe
Photo
Vlad Beskrovnyy:
Ну, вот MIR простой функции, состоящей из двух await'ов других функций (и больше ничего). Я этот свитч имею в виду
Здесь _1 - это первый параметр, т.е. self, т.е. сама реализация фьючера. Видно, что это enum. В _21 записывается дискриминант енама, дальше по нему свитчимся. Ну, собственно, стейтмашина, че...
Kai Ren:
Спасибо за пояснения. Я как-то MIR читать не привык.
Попробуй сделать на чистых футурах без async/.await. Вполне возможно это все те же пляски с генераторами. Там сейчас внутри генератором есть мувы, и это, кстати, боком вылазит в юзер коде с async move {} блоками требую либо Copy либо дополнительных явных клонов.
Vlad Beskrovnyy:
Ну, я бы так не сказал, вроде бы от этого свитча фундаментально не избавиться. Мне просто интересно, почему была выбрана именно такая модель фьючеров, с поллингом всей цепочки. Понимаю, что она была выбрана уже много лет назад, и, вероятно, все уже забыли, но тогда этот выбор должен был быть хорошо мотивирован, полагаю
Вроде звучит разумно, но вот интересно, с тех пор как оно там все Pin, т.е. не может муваться, разве нельзя без аллокаций. А, хотя фьючеры могут быть Unpin...
Ну, вот MIR простой функции, состоящей из двух await'ов других функций (и больше ничего). Я этот свитч имею в виду
Здесь _1 - это первый параметр, т.е. self, т.е. сама реализация фьючера. Видно, что это enum. В _21 записывается дискриминант енама, дальше по нему свитчимся. Ну, собственно, стейтмашина, че...
Kai Ren:
Спасибо за пояснения. Я как-то MIR читать не привык.
Попробуй сделать на чистых футурах без async/.await. Вполне возможно это все те же пляски с генераторами. Там сейчас внутри генератором есть мувы, и это, кстати, боком вылазит в юзер коде с async move {} блоками требую либо Copy либо дополнительных явных клонов.
Vlad Beskrovnyy:
Ну, я бы так не сказал, вроде бы от этого свитча фундаментально не избавиться. Мне просто интересно, почему была выбрана именно такая модель фьючеров, с поллингом всей цепочки. Понимаю, что она была выбрана уже много лет назад, и, вероятно, все уже забыли, но тогда этот выбор должен был быть хорошо мотивирован, полагаю
Вроде звучит разумно, но вот интересно, с тех пор как оно там все Pin, т.е. не может муваться, разве нельзя без аллокаций. А, хотя фьючеры могут быть Unpin...
Forwarded from A64m AL256m qn<cores> I0
ну вот теперь точно
УЛЬТИМЕЙТ 8.10 СНИППЕТ
УЛЬТИМЕЙТ 8.10 СНИППЕТ
{-# language UnliftedNewtypes #-}
{-# language StandaloneKindSignatures #-}
{-# language DataKinds, PolyKinds, ExplicitForAll #-}
{-# language ImportQualifiedPost #-}
{-# language MagicHash, UnboxedTuples #-}
module Foo where
import GHC.Types
import GHC.Prim qualified as Prim
type Arr :: forall k -> k -> TYPE(TupleRep[Int32Rep,Int32Rep,AddrRep])
newtype Arr k a = Arr (# Prim.Int32#, Prim.Int32#, Prim.Addr# #)Forwarded from Αλεχ Zhukovsky
https://habr.com/ru/post/472780/ - в плюсах оно может вот так стрельнуть. В расте - вряд ли
Хабр
Зачем избегать друзей, или как я растерял все свои плюсы
Привет, Хабр. Пару дней назад мне на глаза попался вот этот твит: C++ - Stateful TMP#cpp #cplusplus #Cpp20https://t.co/Q3sh3XtiHC pic.twitter.com/AkCRB2zvrT— Kri...
Зигохистоморфный Препроморфизм:
чтобы при моделировании через фри монады избавится от T -> a нужно энкодить через Free + Coyoneda
λeonid Onokhov:
через GADTs не расширяемо выходит. на каждый тип добавлять конструктор
Зигохистоморфный Препроморфизм:
https://github.com/sacundim/free-operational/blob/master/Control/Monad/Operational/Simple.hs#L24
https://github.com/sacundim/free-operational#example-applicative-version-of-reader
немного описания такого поведения
https://jstimpfle.de/blah/free-monads-gadts.html
ответ Кметта
https://stackoverflow.com/questions/14263363/is-operational-really-isomorphic-to-a-free-monad#comment19859454_14263363
чтобы при моделировании через фри монады избавится от T -> a нужно энкодить через Free + Coyoneda
λeonid Onokhov:
через GADTs не расширяемо выходит. на каждый тип добавлять конструктор
Зигохистоморфный Препроморфизм:
https://github.com/sacundim/free-operational/blob/master/Control/Monad/Operational/Simple.hs#L24
https://github.com/sacundim/free-operational#example-applicative-version-of-reader
немного описания такого поведения
https://jstimpfle.de/blah/free-monads-gadts.html
ответ Кметта
https://stackoverflow.com/questions/14263363/is-operational-really-isomorphic-to-a-free-monad#comment19859454_14263363
GitHub
sacundim/free-operational
Operational-style Applicative, Alternative, Monad and MonadPlus, using free monads. - sacundim/free-operational
Forwarded from Oleg Andreev
Тут интересная история: самый быстрый и аккуратный стек ZKP криптографии написан на Расте: https://medium.com/interstellar/bulletproofs-pre-release-fcb1feb36d4b
Но не потому что компилятор такой быстрый, а потому что язык позволяет всю логику очень аккуратно организовать, от арифметики кривой, до высокоуровневых протоколов. На плюсах никто из тех, кто понимает тему, не осилил бы это. А криптография, которую пишут на си/с++ - это обычно тихий пиздец.
Но не потому что компилятор такой быстрый, а потому что язык позволяет всю логику очень аккуратно организовать, от арифметики кривой, до высокоуровневых протоколов. На плюсах никто из тех, кто понимает тему, не осилил бы это. А криптография, которую пишут на си/с++ - это обычно тихий пиздец.
Medium
Bulletproofs pre-release
We are excited to announce a pre-release version of our Bulletproofs implementation, providing a stable interface for creating and…
Forwarded from Mikail Bagishov
А зачем ему брать разность указателей? Ты уверен, что этот кейс не покрывается уже имеющимися решениями? Например, чтобы узнать расположение поля в структуре, есть крейт memoffset.
Проблема в том, что в текущих типах эта проблема вообще не решается. Коротко от лодочника: https://twitter.com/withoutboats/status/1027702531361857536?s=21
Так что есть мнение что чтобы это так работало нужно было прям вообще сильно иначе всё делать. Ну или жить с "почти" монадами, как впрочем и хаскель живет с "почти" категорией Hask.
Так что есть мнение что чтобы это так работало нужно было прям вообще сильно иначе всё делать. Ну или жить с "почти" монадами, как впрочем и хаскель живет с "почти" категорией Hask.
Twitter
Saoirse Shipwreckt
MONADS AND RUST A THREAD - or - why async/await instead of do notation
И Ivan:
А подскажите, можно ли сделать композицию функции с 2-мя параметрами?
Тоесть
f(g(x), h(y))?
Alexander Vershilov:
compose f g h = \x y -> f (g x) (h y)
((flip . ((.) .)) .) . (.) - для любителей pointfree
Sergey:
Читаемо, поддерживаемо, расширяемо )
Alexander Vershilov:
c f g h = curry (uncurry f . first g . second h)
так человечнее
А подскажите, можно ли сделать композицию функции с 2-мя параметрами?
Тоесть
f(g(x), h(y))?
Alexander Vershilov:
compose f g h = \x y -> f (g x) (h y)
((flip . ((.) .)) .) . (.) - для любителей pointfree
Sergey:
Читаемо, поддерживаемо, расширяемо )
Alexander Vershilov:
c f g h = curry (uncurry f . first g . second h)
так человечнее