Время жизни при десериализации JSON внутри FromForm

У меня проблемы с пониманием отношений между временами жизни в этом коде. По сути, у меня есть Rocket API, который получает некоторые x-www-form-urlencoded данные только с одним ключом: json, Этот ключ интуитивно содержит значение JSON, закодированное с помощью процентного кодирования, структуры Message<T>,

(Я знаю, что это неоптимальный дизайн API, но это реверс-инжиниринг, поэтому у меня нет выбора)

Быть легко используемым в качестве охранника From<Message<T>>Я реализую FromForm, Для этого мне нужно реализовать FromForm<'f> для любого Message<T> где T инвентарь Deserialize<'de>, Я написал свою подпись как impl<'f, 'de, T> FromForm<'f> for Message<T> where T: Deserialize<'de>,

Чтобы фактически выполнить декодирование, я:

  1. Получить "json" ключ данных формы;
  2. URL-декодировать значение;
  3. Разбор JSON содержится в значении.

Выручать как можно скорее. Код, делающий это (явные аннотации типов для удобства читателя):

fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<Self, Self::Error> {
    // Get JSON field
    let encoded: Option<&RawStr> = items.find(|&(k, _)| k.as_str() == "json")
        .map(|(_, v)| v);
    if let None = encoded {
        return Err(MessageFormError::MissingJsonKey);
    }

    // Decode URL-string
    let decoded: Result<String, Utf8Error> = encoded.unwrap().url_decode();
    if let Err(e) = decoded {
        return Err(MessageFormError::InvalidUrl(e));
    }

    // Parse JSON
    let json: String = decoded.unwrap();
    serde_json::from_str::<Self>(&json) // Line 205
        .map_err(|e| MessageFormError::InvalidJson(e))
}

Gist, демонстрирующий проблему методом вставки и запуска (не работает на игровой площадке, поскольку зависит от Rocket).

Насколько я понимаю:

  • &RawStr из encoded имеет жизнь 'f,
  • String создан из этого url_decode, который живет до конца функции
  • serde_json занимает &'x str где 'x не должен совпадать с 'de, и возвращает значение (таким образом, оно доживает до конца функции и, поскольку оно возвращается, выходит за его пределы)

Но, похоже, мое понимание неверно:

205 |         serde_json::from_str::<Self>(&json)
    |                                       ^^^^ does not live long enough
206 |             .map_err(|e| MessageFormError::InvalidJson(e))
207 |     }
    |     - borrowed value only lives until here
    |
note: borrowed value must be valid for the lifetime 'f as defined on the impl at 184:1...
   --> src/transport.rs:184:1
    |
184 | / impl<'f, T> FromForm<'f> for Message<T>
185 | |     where T: Deserialize<'f>
186 | | {
187 | |     type Error = MessageFormError;
...   |
207 | |     }
208 | | }
    | |_^

Что я делаю не так и как правильно вернуть десериализованное значение?

1 ответ

Решение

Этот раздел сайта Serde охватывает Deserialize границы в деталях.


Есть два основных способа написания Deserialize границы черты, будь то в блоке impl или функции или где-либо еще.

  • <'de, T> where T: Deserialize<'de>

    Это означает, что "T может быть десериализован с некоторой жизни". Звонящий решает, что это за жизнь. Обычно это используется, когда вызывающая сторона также предоставляет данные, из которых выполняется десериализация, например, в такой функции, как serde_json::from_str, В этом случае входные данные также должны иметь время жизни 'de Например, это может быть &'de str,

  • <T> where T: DeserializeOwned

    Это означает, что "T может быть десериализован из любой жизни". Вызываемый должен решить, какая жизнь. Обычно это происходит потому, что данные, из которых выполняется десериализация, будут выброшены до возврата из функции, поэтому нельзя допускать, чтобы T заимствовал из нее. В вашем случае данные поступают от URL-декодирования некоторого ввода, а декодированные данные выбрасываются после десериализации T. Другое распространенное использование этой границы - функции, которые десериализуются из потока ввода-вывода, такие как serde_json::from_reader,

    Чтобы сказать это более технически, DeserializeOwned признак эквивалентен признаку признака более высокого ранга for<'de> Deserialize<'de>, Единственная разница DeserializeOwned более интуитивно понятен для чтения. Это означает, что T владеет всеми данными, которые десериализуются.

Замена вашего T: Deserialize<'f> связано с T: DeserializeOwned правильно сообщает, что T нельзя заимствовать из данных, декодированных по URL, потому что данные, декодированные по URL, не переживут T.

Другие вопросы по тегам